{
  "openapi": "3.0.3",
  "info": {
    "title": "Rustybin",
    "description": "A high-performance, all-in-one HTTP stub service for API gateway testing. Built in Rust with axum. Designed to exercise every category of API gateway feature - auth, routing, transformation, rate limiting, AI proxying, and more.",
    "version": "0.6.0",
    "contact": {
      "name": "Rustybin"
    }
  },
  "servers": [
    {
      "url": "http://localhost",
      "description": "HTTP"
    },
    {
      "url": "https://localhost",
      "description": "HTTPS / mTLS"
    }
  ],
  "tags": [
    {
      "name": "Utility",
      "description": "Health, identity, image, and flaky endpoints"
    },
    {
      "name": "Echo",
      "description": "Echo and anything endpoints"
    },
    {
      "name": "Status",
      "description": "HTTP status code responses"
    },
    {
      "name": "Response Shaping",
      "description": "Delay, cache, and response-headers"
    },
    {
      "name": "Redirects & Cookies",
      "description": "Redirect chains and cookie management"
    },
    {
      "name": "Info",
      "description": "IP, date, and time information"
    },
    {
      "name": "Random",
      "description": "UUID, random numbers, and lorem ipsum"
    },
    {
      "name": "Auth",
      "description": "Authentication endpoints (basic, api-key, JWT, mTLS, OIDC)"
    },
    {
      "name": "AI Gateway",
      "description": "OpenAI-compatible AI endpoints"
    },
    {
      "name": "GraphQL",
      "description": "GraphQL API with playground"
    },
    {
      "name": "Orchestration",
      "description": "Multi-step orchestration pipeline"
    },
    {
      "name": "SOAP",
      "description": "SOAP/XML web service"
    },
    {
      "name": "WebSocket",
      "description": "WebSocket echo and server-push endpoints"
    },
    {
      "name": "Control Plane",
      "description": "Request inspector, configuration and version under /_rustybin"
    }
  ],
  "paths": {
    "/": {
      "get": {
        "tags": [
          "Utility"
        ],
        "summary": "Landing page",
        "description": "HTML landing page with endpoint directory and quick-start examples.",
        "operationId": "getLanding",
        "responses": {
          "200": {
            "description": "HTML landing page",
            "content": {
              "text/html": {}
            }
          }
        }
      }
    },
    "/health": {
      "get": {
        "tags": [
          "Utility"
        ],
        "summary": "Health check",
        "description": "Returns service health status with version and instance info.",
        "operationId": "getHealth",
        "responses": {
          "200": {
            "description": "Service is healthy",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "status": {
                      "type": "string",
                      "example": "healthy"
                    },
                    "service": {
                      "type": "string",
                      "example": "rustybin"
                    },
                    "version": {
                      "type": "string",
                      "example": "0.6.0"
                    },
                    "instance_id": {
                      "type": "string",
                      "format": "uuid"
                    }
                  }
                }
              },
              "application/xml": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "status": {
                      "type": "string",
                      "example": "healthy"
                    },
                    "service": {
                      "type": "string",
                      "example": "rustybin"
                    },
                    "version": {
                      "type": "string",
                      "example": "0.6.0"
                    },
                    "instance_id": {
                      "type": "string",
                      "format": "uuid"
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/identity": {
      "get": {
        "tags": [
          "Utility"
        ],
        "summary": "Instance identity",
        "description": "Returns hostname, instance ID, uptime, request count, and port information. Useful for load-balancer testing.",
        "operationId": "getIdentity",
        "responses": {
          "200": {
            "description": "Instance identity information",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/IdentityResponse"
                }
              },
              "application/xml": {
                "schema": {
                  "$ref": "#/components/schemas/IdentityResponse"
                }
              }
            }
          }
        }
      },
      "post": {
        "tags": [
          "Utility"
        ],
        "summary": "Instance identity",
        "description": "Returns hostname, instance ID, uptime, request count, and port information. Useful for load-balancer testing.",
        "operationId": "getIdentity_post",
        "responses": {
          "200": {
            "description": "Instance identity information",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/IdentityResponse"
                }
              },
              "application/xml": {
                "schema": {
                  "$ref": "#/components/schemas/IdentityResponse"
                }
              }
            }
          }
        }
      },
      "put": {
        "tags": [
          "Utility"
        ],
        "summary": "Instance identity",
        "description": "Returns hostname, instance ID, uptime, request count, and port information. Useful for load-balancer testing.",
        "operationId": "getIdentity_put",
        "responses": {
          "200": {
            "description": "Instance identity information",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/IdentityResponse"
                }
              },
              "application/xml": {
                "schema": {
                  "$ref": "#/components/schemas/IdentityResponse"
                }
              }
            }
          }
        }
      },
      "patch": {
        "tags": [
          "Utility"
        ],
        "summary": "Instance identity",
        "description": "Returns hostname, instance ID, uptime, request count, and port information. Useful for load-balancer testing.",
        "operationId": "getIdentity_patch",
        "responses": {
          "200": {
            "description": "Instance identity information",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/IdentityResponse"
                }
              },
              "application/xml": {
                "schema": {
                  "$ref": "#/components/schemas/IdentityResponse"
                }
              }
            }
          }
        }
      },
      "delete": {
        "tags": [
          "Utility"
        ],
        "summary": "Instance identity",
        "description": "Returns hostname, instance ID, uptime, request count, and port information. Useful for load-balancer testing.",
        "operationId": "getIdentity_delete",
        "responses": {
          "200": {
            "description": "Instance identity information",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/IdentityResponse"
                }
              },
              "application/xml": {
                "schema": {
                  "$ref": "#/components/schemas/IdentityResponse"
                }
              }
            }
          }
        }
      }
    },
    "/health/healthy": {
      "post": {
        "tags": [
          "Utility"
        ],
        "summary": "Mark instance healthy",
        "description": "Sets the instance health state to healthy. Subsequent GET /health returns 200.",
        "operationId": "markHealthy",
        "responses": {
          "200": {
            "description": "State changed; the body reports the new state (`status`, `healthy`)",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              },
              "application/xml": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "401": {
            "description": "Admin token required"
          },
          "403": {
            "description": "Disabled in public mode without an admin token"
          }
        }
      }
    },
    "/health/unhealthy": {
      "post": {
        "tags": [
          "Utility"
        ],
        "summary": "Mark instance unhealthy",
        "description": "Sets the instance health state to unhealthy (200 confirms the change). GET /health then returns 503 and the gRPC grpc.health.v1 service reports NOT_SERVING - useful for gateway upstream active health-check failover demos.",
        "operationId": "markUnhealthy",
        "responses": {
          "200": {
            "description": "State changed; the body reports the new state (`status`, `healthy`)",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              },
              "application/xml": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "401": {
            "description": "Admin token required"
          },
          "403": {
            "description": "Disabled in public mode without an admin token"
          }
        }
      }
    },
    "/health/toggle": {
      "post": {
        "tags": [
          "Utility"
        ],
        "summary": "Toggle health state",
        "description": "Flips the current health state between healthy and unhealthy; 200 with the new state.",
        "operationId": "toggleHealth",
        "responses": {
          "200": {
            "description": "State changed; the body reports the new state (`status`, `healthy`)",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              },
              "application/xml": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "401": {
            "description": "Admin token required"
          },
          "403": {
            "description": "Disabled in public mode without an admin token"
          }
        }
      }
    },
    "/ws": {
      "get": {
        "tags": [
          "WebSocket"
        ],
        "summary": "WebSocket echo",
        "description": "Upgrade to a WebSocket connection that echoes every text and binary frame back to the client. The first subprotocol offered in Sec-WebSocket-Protocol is echoed back. Limits: 1 MiB messages (close 1009), 5 min idle and 1 h lifetime (close 1001); 256 KiB, 1 min and 10 min in public mode. Requires the standard WebSocket upgrade headers; a plain GET returns 426 Upgrade Required.",
        "operationId": "wsEcho",
        "responses": {
          "101": {
            "description": "Switching Protocols (WebSocket established)"
          },
          "426": {
            "description": "Upgrade Required (missing WebSocket headers)"
          }
        }
      }
    },
    "/ws/time": {
      "get": {
        "tags": [
          "WebSocket"
        ],
        "summary": "WebSocket timestamp ticker",
        "description": "Upgrade to a WebSocket that pushes the current timestamp on a fixed interval, then closes. Exercises server-initiated frames through the gateway.",
        "operationId": "wsTime",
        "parameters": [
          {
            "name": "interval_ms",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "default": 1000,
              "minimum": 100,
              "maximum": 60000
            },
            "description": "Tick interval in milliseconds"
          },
          {
            "name": "count",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "default": 10,
              "minimum": 1,
              "maximum": 1000
            },
            "description": "Number of ticks before close"
          }
        ],
        "responses": {
          "101": {
            "description": "Switching Protocols (WebSocket established)"
          },
          "426": {
            "description": "Upgrade Required (missing WebSocket headers)"
          }
        }
      }
    },
    "/image": {
      "get": {
        "tags": [
          "Utility"
        ],
        "summary": "Get an image in the format chosen by Accept",
        "description": "Picks webp, svg, jpeg, png or gif from the Accept header (q-values honoured); PNG without Accept; 406 when nothing acceptable is offered.",
        "operationId": "getImage",
        "responses": {
          "200": {
            "description": "Image",
            "content": {
              "image/webp": {
                "schema": {
                  "type": "string",
                  "format": "binary"
                }
              },
              "image/svg+xml": {
                "schema": {
                  "type": "string"
                }
              },
              "image/jpeg": {
                "schema": {
                  "type": "string",
                  "format": "binary"
                }
              },
              "image/png": {
                "schema": {
                  "type": "string",
                  "format": "binary"
                }
              },
              "image/gif": {
                "schema": {
                  "type": "string",
                  "format": "binary"
                }
              }
            }
          },
          "406": {
            "description": "No supported image type acceptable"
          }
        }
      }
    },
    "/image/png": {
      "get": {
        "tags": [
          "Utility"
        ],
        "summary": "Get a png image",
        "description": "Returns a small, valid png test image.",
        "operationId": "getImagePNG",
        "responses": {
          "200": {
            "description": "png image",
            "content": {
              "image/png": {
                "schema": {
                  "type": "string",
                  "format": "binary"
                }
              }
            }
          }
        }
      }
    },
    "/image/jpeg": {
      "get": {
        "tags": [
          "Utility"
        ],
        "summary": "Get a jpeg image",
        "description": "Returns a small, valid jpeg test image.",
        "operationId": "getImageJPEG",
        "responses": {
          "200": {
            "description": "jpeg image",
            "content": {
              "image/jpeg": {
                "schema": {
                  "type": "string",
                  "format": "binary"
                }
              }
            }
          }
        }
      }
    },
    "/image/gif": {
      "get": {
        "tags": [
          "Utility"
        ],
        "summary": "Get a gif image",
        "description": "Returns a small, valid gif test image.",
        "operationId": "getImageGIF",
        "responses": {
          "200": {
            "description": "gif image",
            "content": {
              "image/gif": {
                "schema": {
                  "type": "string",
                  "format": "binary"
                }
              }
            }
          }
        }
      }
    },
    "/image/webp": {
      "get": {
        "tags": [
          "Utility"
        ],
        "summary": "Get a webp image",
        "description": "Returns a small, valid webp test image.",
        "operationId": "getImageWEBP",
        "responses": {
          "200": {
            "description": "webp image",
            "content": {
              "image/webp": {
                "schema": {
                  "type": "string",
                  "format": "binary"
                }
              }
            }
          }
        }
      }
    },
    "/image/svg": {
      "get": {
        "tags": [
          "Utility"
        ],
        "summary": "Get a svg image",
        "description": "Returns a small, valid svg test image.",
        "operationId": "getImageSVG",
        "responses": {
          "200": {
            "description": "svg image",
            "content": {
              "image/svg+xml": {
                "schema": {
                  "type": "string",
                  "format": "binary"
                }
              }
            }
          }
        }
      }
    },
    "/openapi.json": {
      "get": {
        "tags": [
          "Utility"
        ],
        "summary": "OpenAPI spec (JSON)",
        "description": "Returns the full OpenAPI 3.0.3 specification as JSON.",
        "operationId": "getOpenApiJson",
        "responses": {
          "200": {
            "description": "OpenAPI JSON spec"
          }
        }
      }
    },
    "/openapi.yaml": {
      "get": {
        "tags": [
          "Utility"
        ],
        "summary": "OpenAPI spec (YAML)",
        "description": "Returns the full OpenAPI 3.0.3 specification as YAML.",
        "operationId": "getOpenApiYaml",
        "responses": {
          "200": {
            "description": "OpenAPI YAML spec"
          }
        }
      }
    },
    "/docs": {
      "get": {
        "tags": [
          "Utility"
        ],
        "summary": "API documentation UI",
        "description": "Serves a Scalar-powered interactive API documentation page.",
        "operationId": "getDocs",
        "responses": {
          "200": {
            "description": "HTML documentation page",
            "content": {
              "text/html": {}
            }
          }
        }
      }
    },
    "/export/postman.json": {
      "get": {
        "tags": [
          "Utility"
        ],
        "summary": "Postman Collection export",
        "description": "Downloads a Postman Collection v2.1 JSON file with pre-configured requests for all Rustybin endpoints.",
        "operationId": "getExportPostman",
        "responses": {
          "200": {
            "description": "Postman Collection v2.1 JSON",
            "content": {
              "application/json": {}
            },
            "headers": {
              "Content-Disposition": {
                "schema": {
                  "type": "string",
                  "example": "attachment; filename=\"rustybin-postman.json\""
                }
              }
            }
          },
          "400": {
            "description": "Invalid base_url",
            "content": {
              "application/json": {}
            }
          }
        },
        "parameters": [
          {
            "name": "base_url",
            "in": "query",
            "required": false,
            "description": "Base URL written into the export (absolute http(s) URL, optional path prefix). Default: the origin the request used (scheme, Host, and Forwarded / X-Forwarded-* with RUSTYBIN_TRUST_FORWARD).",
            "schema": {
              "type": "string",
              "format": "uri",
              "example": "https://gateway.example.com/rustybin"
            }
          }
        ]
      }
    },
    "/export/insomnia.json": {
      "get": {
        "tags": [
          "Utility"
        ],
        "summary": "Insomnia Collection export",
        "description": "Downloads an Insomnia Export v4 JSON file with pre-configured requests for all Rustybin endpoints.",
        "operationId": "getExportInsomnia",
        "responses": {
          "200": {
            "description": "Insomnia Export v4 JSON",
            "content": {
              "application/json": {}
            },
            "headers": {
              "Content-Disposition": {
                "schema": {
                  "type": "string",
                  "example": "attachment; filename=\"rustybin-insomnia.json\""
                }
              }
            }
          },
          "400": {
            "description": "Invalid base_url",
            "content": {
              "application/json": {}
            }
          }
        },
        "parameters": [
          {
            "name": "base_url",
            "in": "query",
            "required": false,
            "description": "Base URL written into the export (absolute http(s) URL, optional path prefix). Default: the origin the request used (scheme, Host, and Forwarded / X-Forwarded-* with RUSTYBIN_TRUST_FORWARD).",
            "schema": {
              "type": "string",
              "format": "uri",
              "example": "https://gateway.example.com/rustybin"
            }
          }
        ]
      }
    },
    "/export/curl.sh": {
      "get": {
        "tags": [
          "Utility"
        ],
        "summary": "cURL shell script export",
        "description": "Downloads a Bash script with curl commands for all Rustybin endpoints. Set BASE_URL env var to target your instance.",
        "operationId": "getExportCurl",
        "responses": {
          "200": {
            "description": "Bash script with curl commands",
            "content": {
              "text/x-shellscript": {}
            },
            "headers": {
              "Content-Disposition": {
                "schema": {
                  "type": "string",
                  "example": "attachment; filename=\"rustybin-curl.sh\""
                }
              }
            }
          },
          "400": {
            "description": "Invalid base_url",
            "content": {
              "application/json": {}
            }
          }
        },
        "parameters": [
          {
            "name": "base_url",
            "in": "query",
            "required": false,
            "description": "Base URL written into the export (absolute http(s) URL, optional path prefix). Default: the origin the request used (scheme, Host, and Forwarded / X-Forwarded-* with RUSTYBIN_TRUST_FORWARD).",
            "schema": {
              "type": "string",
              "format": "uri",
              "example": "https://gateway.example.com/rustybin"
            }
          }
        ]
      }
    },
    "/export/bruno.json": {
      "get": {
        "tags": [
          "Utility"
        ],
        "summary": "Bruno Collection export",
        "description": "Downloads a Bruno collection JSON file with pre-configured requests for all Rustybin endpoints.",
        "operationId": "getExportBruno",
        "responses": {
          "200": {
            "description": "Bruno Collection JSON",
            "content": {
              "application/json": {}
            },
            "headers": {
              "Content-Disposition": {
                "schema": {
                  "type": "string",
                  "example": "attachment; filename=\"rustybin-bruno.json\""
                }
              }
            }
          },
          "400": {
            "description": "Invalid base_url",
            "content": {
              "application/json": {}
            }
          }
        },
        "parameters": [
          {
            "name": "base_url",
            "in": "query",
            "required": false,
            "description": "Base URL written into the export (absolute http(s) URL, optional path prefix). Default: the origin the request used (scheme, Host, and Forwarded / X-Forwarded-* with RUSTYBIN_TRUST_FORWARD).",
            "schema": {
              "type": "string",
              "format": "uri",
              "example": "https://gateway.example.com/rustybin"
            }
          }
        ]
      }
    },
    "/export/requests.http": {
      "get": {
        "tags": [
          "Utility"
        ],
        "summary": ".http file export",
        "description": "Downloads an HTTP requests file compatible with JetBrains HTTP Client and VS Code REST Client.",
        "operationId": "getExportHttpFile",
        "responses": {
          "200": {
            "description": ".http file with request definitions",
            "content": {
              "text/plain": {}
            },
            "headers": {
              "Content-Disposition": {
                "schema": {
                  "type": "string",
                  "example": "attachment; filename=\"rustybin.http\""
                }
              }
            }
          },
          "400": {
            "description": "Invalid base_url",
            "content": {
              "application/json": {}
            }
          }
        },
        "parameters": [
          {
            "name": "base_url",
            "in": "query",
            "required": false,
            "description": "Base URL written into the export (absolute http(s) URL, optional path prefix). Default: the origin the request used (scheme, Host, and Forwarded / X-Forwarded-* with RUSTYBIN_TRUST_FORWARD).",
            "schema": {
              "type": "string",
              "format": "uri",
              "example": "https://gateway.example.com/rustybin"
            }
          }
        ]
      }
    },
    "/export/requests.hurl": {
      "get": {
        "tags": [
          "Utility"
        ],
        "summary": "Hurl file export",
        "description": "Downloads a Hurl file with HTTP request definitions and response assertions for all Rustybin endpoints.",
        "operationId": "getExportHurl",
        "responses": {
          "200": {
            "description": "Hurl file with request definitions",
            "content": {
              "text/plain": {}
            },
            "headers": {
              "Content-Disposition": {
                "schema": {
                  "type": "string",
                  "example": "attachment; filename=\"rustybin.hurl\""
                }
              }
            }
          },
          "400": {
            "description": "Invalid base_url",
            "content": {
              "application/json": {}
            }
          }
        },
        "parameters": [
          {
            "name": "base_url",
            "in": "query",
            "required": false,
            "description": "Base URL written into the export (absolute http(s) URL, optional path prefix). Default: the origin the request used (scheme, Host, and Forwarded / X-Forwarded-* with RUSTYBIN_TRUST_FORWARD).",
            "schema": {
              "type": "string",
              "format": "uri",
              "example": "https://gateway.example.com/rustybin"
            }
          }
        ]
      }
    },
    "/export/k6.js": {
      "get": {
        "tags": [
          "Utility"
        ],
        "summary": "k6 load test script export",
        "description": "Downloads a Grafana k6 JavaScript load test script for all Rustybin endpoints. Set BASE_URL env var to target your instance.",
        "operationId": "getExportK6",
        "responses": {
          "200": {
            "description": "k6 JavaScript load test script",
            "content": {
              "application/javascript": {}
            },
            "headers": {
              "Content-Disposition": {
                "schema": {
                  "type": "string",
                  "example": "attachment; filename=\"rustybin-k6.js\""
                }
              }
            }
          },
          "400": {
            "description": "Invalid base_url",
            "content": {
              "application/json": {}
            }
          }
        },
        "parameters": [
          {
            "name": "base_url",
            "in": "query",
            "required": false,
            "description": "Base URL written into the export (absolute http(s) URL, optional path prefix). Default: the origin the request used (scheme, Host, and Forwarded / X-Forwarded-* with RUSTYBIN_TRUST_FORWARD).",
            "schema": {
              "type": "string",
              "format": "uri",
              "example": "https://gateway.example.com/rustybin"
            }
          }
        ]
      }
    },
    "/export/har.json": {
      "get": {
        "tags": [
          "Utility"
        ],
        "summary": "HAR 1.2 archive export",
        "description": "Downloads an HTTP Archive (HAR) 1.2 JSON file with request entries for all Rustybin endpoints.",
        "operationId": "getExportHar",
        "responses": {
          "200": {
            "description": "HAR 1.2 JSON archive",
            "content": {
              "application/json": {}
            },
            "headers": {
              "Content-Disposition": {
                "schema": {
                  "type": "string",
                  "example": "attachment; filename=\"rustybin.har.json\""
                }
              }
            }
          },
          "400": {
            "description": "Invalid base_url",
            "content": {
              "application/json": {}
            }
          }
        },
        "parameters": [
          {
            "name": "base_url",
            "in": "query",
            "required": false,
            "description": "Base URL written into the export (absolute http(s) URL, optional path prefix). Default: the origin the request used (scheme, Host, and Forwarded / X-Forwarded-* with RUSTYBIN_TRUST_FORWARD).",
            "schema": {
              "type": "string",
              "format": "uri",
              "example": "https://gateway.example.com/rustybin"
            }
          }
        ]
      }
    },
    "/flaky/{fail_rate}": {
      "get": {
        "tags": [
          "Utility"
        ],
        "summary": "Random failure by rate",
        "description": "Fails fail_rate% of the time with 503. Useful for circuit-breaker and health-check testing.",
        "operationId": "getFlakyRate",
        "parameters": [
          {
            "name": "fail_rate",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer",
              "minimum": 0,
              "maximum": 100
            },
            "description": "Failure percentage (0=never fail, 100=always fail)"
          }
        ],
        "responses": {
          "200": {
            "description": "Request succeeded",
            "headers": {
              "X-Rustybin-Flaky": {
                "schema": {
                  "type": "string",
                  "example": "true"
                }
              },
              "X-Rustybin-Fail-Rate": {
                "schema": {
                  "type": "integer"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/FlakySuccess"
                }
              },
              "application/xml": {
                "schema": {
                  "$ref": "#/components/schemas/FlakySuccess"
                }
              }
            }
          },
          "400": {
            "description": "Invalid fail_rate",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              },
              "application/xml": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "503": {
            "description": "Simulated failure",
            "headers": {
              "X-Rustybin-Flaky": {
                "schema": {
                  "type": "string",
                  "example": "true"
                }
              },
              "X-Rustybin-Fail-Rate": {
                "schema": {
                  "type": "integer"
                }
              },
              "Retry-After": {
                "schema": {
                  "type": "integer",
                  "example": 1
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/FlakyFailure"
                }
              },
              "application/xml": {
                "schema": {
                  "$ref": "#/components/schemas/FlakyFailure"
                }
              }
            }
          }
        }
      },
      "post": {
        "tags": [
          "Utility"
        ],
        "summary": "Random failure by rate",
        "description": "Fails fail_rate% of the time with 503. Useful for circuit-breaker and health-check testing.",
        "operationId": "getFlakyRate_post",
        "parameters": [
          {
            "name": "fail_rate",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer",
              "minimum": 0,
              "maximum": 100
            },
            "description": "Failure percentage (0=never fail, 100=always fail)"
          }
        ],
        "responses": {
          "200": {
            "description": "Request succeeded",
            "headers": {
              "X-Rustybin-Flaky": {
                "schema": {
                  "type": "string",
                  "example": "true"
                }
              },
              "X-Rustybin-Fail-Rate": {
                "schema": {
                  "type": "integer"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/FlakySuccess"
                }
              },
              "application/xml": {
                "schema": {
                  "$ref": "#/components/schemas/FlakySuccess"
                }
              }
            }
          },
          "400": {
            "description": "Invalid fail_rate",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              },
              "application/xml": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "503": {
            "description": "Simulated failure",
            "headers": {
              "X-Rustybin-Flaky": {
                "schema": {
                  "type": "string",
                  "example": "true"
                }
              },
              "X-Rustybin-Fail-Rate": {
                "schema": {
                  "type": "integer"
                }
              },
              "Retry-After": {
                "schema": {
                  "type": "integer",
                  "example": 1
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/FlakyFailure"
                }
              },
              "application/xml": {
                "schema": {
                  "$ref": "#/components/schemas/FlakyFailure"
                }
              }
            }
          }
        }
      },
      "put": {
        "tags": [
          "Utility"
        ],
        "summary": "Random failure by rate",
        "description": "Fails fail_rate% of the time with 503. Useful for circuit-breaker and health-check testing.",
        "operationId": "getFlakyRate_put",
        "parameters": [
          {
            "name": "fail_rate",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer",
              "minimum": 0,
              "maximum": 100
            },
            "description": "Failure percentage (0=never fail, 100=always fail)"
          }
        ],
        "responses": {
          "200": {
            "description": "Request succeeded",
            "headers": {
              "X-Rustybin-Flaky": {
                "schema": {
                  "type": "string",
                  "example": "true"
                }
              },
              "X-Rustybin-Fail-Rate": {
                "schema": {
                  "type": "integer"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/FlakySuccess"
                }
              },
              "application/xml": {
                "schema": {
                  "$ref": "#/components/schemas/FlakySuccess"
                }
              }
            }
          },
          "400": {
            "description": "Invalid fail_rate",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              },
              "application/xml": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "503": {
            "description": "Simulated failure",
            "headers": {
              "X-Rustybin-Flaky": {
                "schema": {
                  "type": "string",
                  "example": "true"
                }
              },
              "X-Rustybin-Fail-Rate": {
                "schema": {
                  "type": "integer"
                }
              },
              "Retry-After": {
                "schema": {
                  "type": "integer",
                  "example": 1
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/FlakyFailure"
                }
              },
              "application/xml": {
                "schema": {
                  "$ref": "#/components/schemas/FlakyFailure"
                }
              }
            }
          }
        }
      },
      "patch": {
        "tags": [
          "Utility"
        ],
        "summary": "Random failure by rate",
        "description": "Fails fail_rate% of the time with 503. Useful for circuit-breaker and health-check testing.",
        "operationId": "getFlakyRate_patch",
        "parameters": [
          {
            "name": "fail_rate",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer",
              "minimum": 0,
              "maximum": 100
            },
            "description": "Failure percentage (0=never fail, 100=always fail)"
          }
        ],
        "responses": {
          "200": {
            "description": "Request succeeded",
            "headers": {
              "X-Rustybin-Flaky": {
                "schema": {
                  "type": "string",
                  "example": "true"
                }
              },
              "X-Rustybin-Fail-Rate": {
                "schema": {
                  "type": "integer"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/FlakySuccess"
                }
              },
              "application/xml": {
                "schema": {
                  "$ref": "#/components/schemas/FlakySuccess"
                }
              }
            }
          },
          "400": {
            "description": "Invalid fail_rate",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              },
              "application/xml": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "503": {
            "description": "Simulated failure",
            "headers": {
              "X-Rustybin-Flaky": {
                "schema": {
                  "type": "string",
                  "example": "true"
                }
              },
              "X-Rustybin-Fail-Rate": {
                "schema": {
                  "type": "integer"
                }
              },
              "Retry-After": {
                "schema": {
                  "type": "integer",
                  "example": 1
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/FlakyFailure"
                }
              },
              "application/xml": {
                "schema": {
                  "$ref": "#/components/schemas/FlakyFailure"
                }
              }
            }
          }
        }
      },
      "delete": {
        "tags": [
          "Utility"
        ],
        "summary": "Random failure by rate",
        "description": "Fails fail_rate% of the time with 503. Useful for circuit-breaker and health-check testing.",
        "operationId": "getFlakyRate_delete",
        "parameters": [
          {
            "name": "fail_rate",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer",
              "minimum": 0,
              "maximum": 100
            },
            "description": "Failure percentage (0=never fail, 100=always fail)"
          }
        ],
        "responses": {
          "200": {
            "description": "Request succeeded",
            "headers": {
              "X-Rustybin-Flaky": {
                "schema": {
                  "type": "string",
                  "example": "true"
                }
              },
              "X-Rustybin-Fail-Rate": {
                "schema": {
                  "type": "integer"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/FlakySuccess"
                }
              },
              "application/xml": {
                "schema": {
                  "$ref": "#/components/schemas/FlakySuccess"
                }
              }
            }
          },
          "400": {
            "description": "Invalid fail_rate",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              },
              "application/xml": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "503": {
            "description": "Simulated failure",
            "headers": {
              "X-Rustybin-Flaky": {
                "schema": {
                  "type": "string",
                  "example": "true"
                }
              },
              "X-Rustybin-Fail-Rate": {
                "schema": {
                  "type": "integer"
                }
              },
              "Retry-After": {
                "schema": {
                  "type": "integer",
                  "example": 1
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/FlakyFailure"
                }
              },
              "application/xml": {
                "schema": {
                  "$ref": "#/components/schemas/FlakyFailure"
                }
              }
            }
          }
        }
      }
    },
    "/flaky/pattern/{pattern}": {
      "get": {
        "tags": [
          "Utility"
        ],
        "summary": "Deterministic success/fail pattern",
        "description": "Follows a repeating pattern of S (success/200) and F (fail/503). E.g. SSFSF cycles through: success, success, fail, success, fail.",
        "operationId": "getFlakyPattern",
        "parameters": [
          {
            "name": "pattern",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "pattern": "^[SsFf]+$"
            },
            "example": "SSFSF",
            "description": "Pattern of S (success) and F (fail) characters"
          }
        ],
        "responses": {
          "200": {
            "description": "Pattern position is S (success)"
          },
          "400": {
            "description": "Invalid pattern (must contain only S and F)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              },
              "application/xml": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "503": {
            "description": "Pattern position is F (fail)"
          }
        }
      },
      "post": {
        "tags": [
          "Utility"
        ],
        "summary": "Deterministic success/fail pattern",
        "description": "Follows a repeating pattern of S (success/200) and F (fail/503). E.g. SSFSF cycles through: success, success, fail, success, fail.",
        "operationId": "getFlakyPattern_post",
        "parameters": [
          {
            "name": "pattern",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "pattern": "^[SsFf]+$"
            },
            "example": "SSFSF",
            "description": "Pattern of S (success) and F (fail) characters"
          }
        ],
        "responses": {
          "200": {
            "description": "Pattern position is S (success)"
          },
          "400": {
            "description": "Invalid pattern (must contain only S and F)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              },
              "application/xml": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "503": {
            "description": "Pattern position is F (fail)"
          }
        }
      },
      "put": {
        "tags": [
          "Utility"
        ],
        "summary": "Deterministic success/fail pattern",
        "description": "Follows a repeating pattern of S (success/200) and F (fail/503). E.g. SSFSF cycles through: success, success, fail, success, fail.",
        "operationId": "getFlakyPattern_put",
        "parameters": [
          {
            "name": "pattern",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "pattern": "^[SsFf]+$"
            },
            "example": "SSFSF",
            "description": "Pattern of S (success) and F (fail) characters"
          }
        ],
        "responses": {
          "200": {
            "description": "Pattern position is S (success)"
          },
          "400": {
            "description": "Invalid pattern (must contain only S and F)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              },
              "application/xml": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "503": {
            "description": "Pattern position is F (fail)"
          }
        }
      },
      "patch": {
        "tags": [
          "Utility"
        ],
        "summary": "Deterministic success/fail pattern",
        "description": "Follows a repeating pattern of S (success/200) and F (fail/503). E.g. SSFSF cycles through: success, success, fail, success, fail.",
        "operationId": "getFlakyPattern_patch",
        "parameters": [
          {
            "name": "pattern",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "pattern": "^[SsFf]+$"
            },
            "example": "SSFSF",
            "description": "Pattern of S (success) and F (fail) characters"
          }
        ],
        "responses": {
          "200": {
            "description": "Pattern position is S (success)"
          },
          "400": {
            "description": "Invalid pattern (must contain only S and F)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              },
              "application/xml": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "503": {
            "description": "Pattern position is F (fail)"
          }
        }
      },
      "delete": {
        "tags": [
          "Utility"
        ],
        "summary": "Deterministic success/fail pattern",
        "description": "Follows a repeating pattern of S (success/200) and F (fail/503). E.g. SSFSF cycles through: success, success, fail, success, fail.",
        "operationId": "getFlakyPattern_delete",
        "parameters": [
          {
            "name": "pattern",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "pattern": "^[SsFf]+$"
            },
            "example": "SSFSF",
            "description": "Pattern of S (success) and F (fail) characters"
          }
        ],
        "responses": {
          "200": {
            "description": "Pattern position is S (success)"
          },
          "400": {
            "description": "Invalid pattern (must contain only S and F)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              },
              "application/xml": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "503": {
            "description": "Pattern position is F (fail)"
          }
        }
      }
    },
    "/flaky/after/{n}": {
      "get": {
        "tags": [
          "Utility"
        ],
        "summary": "Succeed then fail after N requests",
        "description": "Succeeds for the first N requests, then fails forever (until reset). Simulates an upstream that goes down.",
        "operationId": "getFlakyAfter",
        "parameters": [
          {
            "name": "n",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer",
              "minimum": 0
            },
            "description": "Number of successful requests before failing"
          }
        ],
        "responses": {
          "200": {
            "description": "Request succeeded (within first N requests)"
          },
          "503": {
            "description": "Service unavailable (after N requests)"
          }
        }
      },
      "post": {
        "tags": [
          "Utility"
        ],
        "summary": "Succeed then fail after N requests",
        "description": "Succeeds for the first N requests, then fails forever (until reset). Simulates an upstream that goes down.",
        "operationId": "getFlakyAfter_post",
        "parameters": [
          {
            "name": "n",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer",
              "minimum": 0
            },
            "description": "Number of successful requests before failing"
          }
        ],
        "responses": {
          "200": {
            "description": "Request succeeded (within first N requests)"
          },
          "503": {
            "description": "Service unavailable (after N requests)"
          }
        }
      },
      "put": {
        "tags": [
          "Utility"
        ],
        "summary": "Succeed then fail after N requests",
        "description": "Succeeds for the first N requests, then fails forever (until reset). Simulates an upstream that goes down.",
        "operationId": "getFlakyAfter_put",
        "parameters": [
          {
            "name": "n",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer",
              "minimum": 0
            },
            "description": "Number of successful requests before failing"
          }
        ],
        "responses": {
          "200": {
            "description": "Request succeeded (within first N requests)"
          },
          "503": {
            "description": "Service unavailable (after N requests)"
          }
        }
      },
      "patch": {
        "tags": [
          "Utility"
        ],
        "summary": "Succeed then fail after N requests",
        "description": "Succeeds for the first N requests, then fails forever (until reset). Simulates an upstream that goes down.",
        "operationId": "getFlakyAfter_patch",
        "parameters": [
          {
            "name": "n",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer",
              "minimum": 0
            },
            "description": "Number of successful requests before failing"
          }
        ],
        "responses": {
          "200": {
            "description": "Request succeeded (within first N requests)"
          },
          "503": {
            "description": "Service unavailable (after N requests)"
          }
        }
      },
      "delete": {
        "tags": [
          "Utility"
        ],
        "summary": "Succeed then fail after N requests",
        "description": "Succeeds for the first N requests, then fails forever (until reset). Simulates an upstream that goes down.",
        "operationId": "getFlakyAfter_delete",
        "parameters": [
          {
            "name": "n",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer",
              "minimum": 0
            },
            "description": "Number of successful requests before failing"
          }
        ],
        "responses": {
          "200": {
            "description": "Request succeeded (within first N requests)"
          },
          "503": {
            "description": "Service unavailable (after N requests)"
          }
        }
      }
    },
    "/flaky/recover/{n}": {
      "get": {
        "tags": [
          "Utility"
        ],
        "summary": "Fail then recover after N requests",
        "description": "Fails for the first N requests, then succeeds forever. Simulates an upstream recovering.",
        "operationId": "getFlakyRecover",
        "parameters": [
          {
            "name": "n",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer",
              "minimum": 0
            },
            "description": "Number of failing requests before recovering"
          }
        ],
        "responses": {
          "200": {
            "description": "Request succeeded (after N requests)"
          },
          "503": {
            "description": "Service unavailable (within first N requests)"
          }
        }
      },
      "post": {
        "tags": [
          "Utility"
        ],
        "summary": "Fail then recover after N requests",
        "description": "Fails for the first N requests, then succeeds forever. Simulates an upstream recovering.",
        "operationId": "getFlakyRecover_post",
        "parameters": [
          {
            "name": "n",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer",
              "minimum": 0
            },
            "description": "Number of failing requests before recovering"
          }
        ],
        "responses": {
          "200": {
            "description": "Request succeeded (after N requests)"
          },
          "503": {
            "description": "Service unavailable (within first N requests)"
          }
        }
      },
      "put": {
        "tags": [
          "Utility"
        ],
        "summary": "Fail then recover after N requests",
        "description": "Fails for the first N requests, then succeeds forever. Simulates an upstream recovering.",
        "operationId": "getFlakyRecover_put",
        "parameters": [
          {
            "name": "n",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer",
              "minimum": 0
            },
            "description": "Number of failing requests before recovering"
          }
        ],
        "responses": {
          "200": {
            "description": "Request succeeded (after N requests)"
          },
          "503": {
            "description": "Service unavailable (within first N requests)"
          }
        }
      },
      "patch": {
        "tags": [
          "Utility"
        ],
        "summary": "Fail then recover after N requests",
        "description": "Fails for the first N requests, then succeeds forever. Simulates an upstream recovering.",
        "operationId": "getFlakyRecover_patch",
        "parameters": [
          {
            "name": "n",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer",
              "minimum": 0
            },
            "description": "Number of failing requests before recovering"
          }
        ],
        "responses": {
          "200": {
            "description": "Request succeeded (after N requests)"
          },
          "503": {
            "description": "Service unavailable (within first N requests)"
          }
        }
      },
      "delete": {
        "tags": [
          "Utility"
        ],
        "summary": "Fail then recover after N requests",
        "description": "Fails for the first N requests, then succeeds forever. Simulates an upstream recovering.",
        "operationId": "getFlakyRecover_delete",
        "parameters": [
          {
            "name": "n",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer",
              "minimum": 0
            },
            "description": "Number of failing requests before recovering"
          }
        ],
        "responses": {
          "200": {
            "description": "Request succeeded (after N requests)"
          },
          "503": {
            "description": "Service unavailable (within first N requests)"
          }
        }
      }
    },
    "/flaky/reset": {
      "post": {
        "tags": [
          "Utility"
        ],
        "summary": "Reset flaky counters",
        "description": "Counters are kept per (session, route): the session is X-Rustybin-Session (else the client IP), the route the endpoint plus its parameter. Without `scope` the caller's own counters are reset (open). `scope=all` resets every client's counters and is admin-guarded.",
        "operationId": "resetFlaky",
        "parameters": [
          {
            "name": "scope",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "enum": [
                "session",
                "all"
              ],
              "default": "session"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Counters reset",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "status": {
                      "type": "string",
                      "example": "reset"
                    },
                    "scope": {
                      "type": "string",
                      "example": "session"
                    },
                    "session": {
                      "type": "string",
                      "example": "ip:203.0.113.9"
                    },
                    "counters_removed": {
                      "type": "integer",
                      "example": 2
                    }
                  }
                }
              },
              "application/xml": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "status": {
                      "type": "string",
                      "example": "reset"
                    },
                    "scope": {
                      "type": "string",
                      "example": "session"
                    },
                    "session": {
                      "type": "string",
                      "example": "ip:203.0.113.9"
                    },
                    "counters_removed": {
                      "type": "integer",
                      "example": 2
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "scope=all without the admin token"
          }
        }
      }
    },
    "/flaky/status": {
      "get": {
        "tags": [
          "Utility"
        ],
        "summary": "Flaky endpoint counter status",
        "description": "Returns the caller's flaky counters (per session and route).",
        "operationId": "getFlakyStatus",
        "responses": {
          "200": {
            "description": "Current counter values",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "session": {
                      "type": "string"
                    },
                    "counters": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "route": {
                            "type": "string",
                            "example": "after:3"
                          },
                          "count": {
                            "type": "integer"
                          }
                        }
                      }
                    }
                  }
                }
              },
              "application/xml": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "session": {
                      "type": "string"
                    },
                    "counters": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "route": {
                            "type": "string",
                            "example": "after:3"
                          },
                          "count": {
                            "type": "integer"
                          }
                        }
                      }
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/echo": {
      "get": {
        "tags": [
          "Echo"
        ],
        "summary": "echo - echo request details",
        "description": "Returns all details of the incoming request: method, headers, query params, body. Supports all HTTP methods.",
        "operationId": "getEcho",
        "responses": {
          "200": {
            "description": "Request details",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/EchoResponse"
                }
              },
              "application/xml": {
                "schema": {
                  "$ref": "#/components/schemas/EchoResponse"
                }
              }
            }
          }
        }
      },
      "post": {
        "tags": [
          "Echo"
        ],
        "summary": "echo - echo request with body",
        "operationId": "postEcho",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {}
            },
            "text/plain": {
              "schema": {
                "type": "string"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Request details with body",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/EchoResponse"
                }
              },
              "application/xml": {
                "schema": {
                  "$ref": "#/components/schemas/EchoResponse"
                }
              }
            }
          }
        }
      },
      "put": {
        "tags": [
          "Echo"
        ],
        "summary": "echo - PUT",
        "operationId": "putEcho",
        "responses": {
          "200": {
            "description": "Request details"
          }
        }
      },
      "delete": {
        "tags": [
          "Echo"
        ],
        "summary": "echo - DELETE",
        "operationId": "deleteEcho",
        "responses": {
          "200": {
            "description": "Request details"
          }
        }
      },
      "patch": {
        "tags": [
          "Echo"
        ],
        "summary": "echo - PATCH",
        "operationId": "patchEcho",
        "responses": {
          "200": {
            "description": "Request details"
          }
        }
      }
    },
    "/echo/{subpath}": {
      "get": {
        "tags": [
          "Echo"
        ],
        "summary": "echo with sub-path",
        "operationId": "getEchoSubPath",
        "parameters": [
          {
            "name": "subpath",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Arbitrary sub-path (captured in response)"
          }
        ],
        "responses": {
          "200": {
            "description": "Request details",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/EchoResponse"
                }
              },
              "application/xml": {
                "schema": {
                  "$ref": "#/components/schemas/EchoResponse"
                }
              }
            }
          }
        }
      },
      "post": {
        "tags": [
          "Echo"
        ],
        "summary": "echo with sub-path",
        "operationId": "getEchoSubPath_post",
        "parameters": [
          {
            "name": "subpath",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Arbitrary sub-path (captured in response)"
          }
        ],
        "responses": {
          "200": {
            "description": "Request details",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/EchoResponse"
                }
              },
              "application/xml": {
                "schema": {
                  "$ref": "#/components/schemas/EchoResponse"
                }
              }
            }
          }
        }
      },
      "put": {
        "tags": [
          "Echo"
        ],
        "summary": "echo with sub-path",
        "operationId": "getEchoSubPath_put",
        "parameters": [
          {
            "name": "subpath",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Arbitrary sub-path (captured in response)"
          }
        ],
        "responses": {
          "200": {
            "description": "Request details",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/EchoResponse"
                }
              },
              "application/xml": {
                "schema": {
                  "$ref": "#/components/schemas/EchoResponse"
                }
              }
            }
          }
        }
      },
      "patch": {
        "tags": [
          "Echo"
        ],
        "summary": "echo with sub-path",
        "operationId": "getEchoSubPath_patch",
        "parameters": [
          {
            "name": "subpath",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Arbitrary sub-path (captured in response)"
          }
        ],
        "responses": {
          "200": {
            "description": "Request details",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/EchoResponse"
                }
              },
              "application/xml": {
                "schema": {
                  "$ref": "#/components/schemas/EchoResponse"
                }
              }
            }
          }
        }
      },
      "delete": {
        "tags": [
          "Echo"
        ],
        "summary": "echo with sub-path",
        "operationId": "getEchoSubPath_delete",
        "parameters": [
          {
            "name": "subpath",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Arbitrary sub-path (captured in response)"
          }
        ],
        "responses": {
          "200": {
            "description": "Request details",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/EchoResponse"
                }
              },
              "application/xml": {
                "schema": {
                  "$ref": "#/components/schemas/EchoResponse"
                }
              }
            }
          }
        }
      }
    },
    "/anything": {
      "get": {
        "tags": [
          "Echo"
        ],
        "summary": "anything - echo request details",
        "description": "Returns all details of the incoming request: method, headers, query params, body. Supports all HTTP methods.",
        "operationId": "getAnything",
        "responses": {
          "200": {
            "description": "Request details",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/EchoResponse"
                }
              },
              "application/xml": {
                "schema": {
                  "$ref": "#/components/schemas/EchoResponse"
                }
              }
            }
          }
        }
      },
      "post": {
        "tags": [
          "Echo"
        ],
        "summary": "anything - echo request with body",
        "operationId": "postAnything",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {}
            },
            "text/plain": {
              "schema": {
                "type": "string"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Request details with body",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/EchoResponse"
                }
              },
              "application/xml": {
                "schema": {
                  "$ref": "#/components/schemas/EchoResponse"
                }
              }
            }
          }
        }
      },
      "put": {
        "tags": [
          "Echo"
        ],
        "summary": "anything - PUT",
        "operationId": "putAnything",
        "responses": {
          "200": {
            "description": "Request details"
          }
        }
      },
      "delete": {
        "tags": [
          "Echo"
        ],
        "summary": "anything - DELETE",
        "operationId": "deleteAnything",
        "responses": {
          "200": {
            "description": "Request details"
          }
        }
      },
      "patch": {
        "tags": [
          "Echo"
        ],
        "summary": "anything - PATCH",
        "operationId": "patchAnything",
        "responses": {
          "200": {
            "description": "Request details"
          }
        }
      }
    },
    "/anything/{subpath}": {
      "get": {
        "tags": [
          "Echo"
        ],
        "summary": "anything with sub-path",
        "operationId": "getAnythingSubPath",
        "parameters": [
          {
            "name": "subpath",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Arbitrary sub-path (captured in response)"
          }
        ],
        "responses": {
          "200": {
            "description": "Request details",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/EchoResponse"
                }
              },
              "application/xml": {
                "schema": {
                  "$ref": "#/components/schemas/EchoResponse"
                }
              }
            }
          }
        }
      },
      "post": {
        "tags": [
          "Echo"
        ],
        "summary": "anything with sub-path",
        "operationId": "getAnythingSubPath_post",
        "parameters": [
          {
            "name": "subpath",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Arbitrary sub-path (captured in response)"
          }
        ],
        "responses": {
          "200": {
            "description": "Request details",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/EchoResponse"
                }
              },
              "application/xml": {
                "schema": {
                  "$ref": "#/components/schemas/EchoResponse"
                }
              }
            }
          }
        }
      },
      "put": {
        "tags": [
          "Echo"
        ],
        "summary": "anything with sub-path",
        "operationId": "getAnythingSubPath_put",
        "parameters": [
          {
            "name": "subpath",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Arbitrary sub-path (captured in response)"
          }
        ],
        "responses": {
          "200": {
            "description": "Request details",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/EchoResponse"
                }
              },
              "application/xml": {
                "schema": {
                  "$ref": "#/components/schemas/EchoResponse"
                }
              }
            }
          }
        }
      },
      "patch": {
        "tags": [
          "Echo"
        ],
        "summary": "anything with sub-path",
        "operationId": "getAnythingSubPath_patch",
        "parameters": [
          {
            "name": "subpath",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Arbitrary sub-path (captured in response)"
          }
        ],
        "responses": {
          "200": {
            "description": "Request details",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/EchoResponse"
                }
              },
              "application/xml": {
                "schema": {
                  "$ref": "#/components/schemas/EchoResponse"
                }
              }
            }
          }
        }
      },
      "delete": {
        "tags": [
          "Echo"
        ],
        "summary": "anything with sub-path",
        "operationId": "getAnythingSubPath_delete",
        "parameters": [
          {
            "name": "subpath",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Arbitrary sub-path (captured in response)"
          }
        ],
        "responses": {
          "200": {
            "description": "Request details",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/EchoResponse"
                }
              },
              "application/xml": {
                "schema": {
                  "$ref": "#/components/schemas/EchoResponse"
                }
              }
            }
          }
        }
      }
    },
    "/status/{code}": {
      "get": {
        "tags": [
          "Status"
        ],
        "summary": "Return a specific HTTP status code (or a weighted random choice)",
        "description": "Returns the specified HTTP status code (200-599). 1xx codes return 400 with a JSON explanation: they are interim responses and cannot be sent as a final response. `200,500` picks uniformly, `200:0.9,500:0.1` by relative weight (up to 20 codes). Redirect codes (301, 302, 303, 307, 308) include `Location: /echo`; 401 adds WWW-Authenticate, 407 Proxy-Authenticate, 429 and 503 Retry-After. 204, 205 and 304 return empty bodies.",
        "operationId": "getStatus",
        "parameters": [
          {
            "name": "code",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "pattern": "^[0-9]{3}(:[0-9.]+)?(,[0-9]{3}(:[0-9.]+)?)*$"
            },
            "example": "200:0.9,500:0.1",
            "description": "Status code, or comma-separated codes with optional :weight"
          }
        ],
        "responses": {
          "200": {
            "description": "Success response",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "status": {
                      "type": "integer"
                    },
                    "chosen_from": {
                      "type": "string"
                    }
                  }
                }
              },
              "application/xml": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "status": {
                      "type": "integer"
                    },
                    "chosen_from": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Invalid or informational (1xx) status code",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              },
              "application/xml": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          }
        }
      },
      "post": {
        "tags": [
          "Status"
        ],
        "summary": "Return a specific HTTP status code (or a weighted random choice)",
        "description": "Returns the specified HTTP status code (200-599). 1xx codes return 400 with a JSON explanation: they are interim responses and cannot be sent as a final response. `200,500` picks uniformly, `200:0.9,500:0.1` by relative weight (up to 20 codes). Redirect codes (301, 302, 303, 307, 308) include `Location: /echo`; 401 adds WWW-Authenticate, 407 Proxy-Authenticate, 429 and 503 Retry-After. 204, 205 and 304 return empty bodies.",
        "operationId": "getStatus_post",
        "parameters": [
          {
            "name": "code",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "pattern": "^[0-9]{3}(:[0-9.]+)?(,[0-9]{3}(:[0-9.]+)?)*$"
            },
            "example": "200:0.9,500:0.1",
            "description": "Status code, or comma-separated codes with optional :weight"
          }
        ],
        "responses": {
          "200": {
            "description": "Success response",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "status": {
                      "type": "integer"
                    },
                    "chosen_from": {
                      "type": "string"
                    }
                  }
                }
              },
              "application/xml": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "status": {
                      "type": "integer"
                    },
                    "chosen_from": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Invalid or informational (1xx) status code",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              },
              "application/xml": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          }
        }
      },
      "put": {
        "tags": [
          "Status"
        ],
        "summary": "Return a specific HTTP status code (or a weighted random choice)",
        "description": "Returns the specified HTTP status code (200-599). 1xx codes return 400 with a JSON explanation: they are interim responses and cannot be sent as a final response. `200,500` picks uniformly, `200:0.9,500:0.1` by relative weight (up to 20 codes). Redirect codes (301, 302, 303, 307, 308) include `Location: /echo`; 401 adds WWW-Authenticate, 407 Proxy-Authenticate, 429 and 503 Retry-After. 204, 205 and 304 return empty bodies.",
        "operationId": "getStatus_put",
        "parameters": [
          {
            "name": "code",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "pattern": "^[0-9]{3}(:[0-9.]+)?(,[0-9]{3}(:[0-9.]+)?)*$"
            },
            "example": "200:0.9,500:0.1",
            "description": "Status code, or comma-separated codes with optional :weight"
          }
        ],
        "responses": {
          "200": {
            "description": "Success response",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "status": {
                      "type": "integer"
                    },
                    "chosen_from": {
                      "type": "string"
                    }
                  }
                }
              },
              "application/xml": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "status": {
                      "type": "integer"
                    },
                    "chosen_from": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Invalid or informational (1xx) status code",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              },
              "application/xml": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          }
        }
      },
      "patch": {
        "tags": [
          "Status"
        ],
        "summary": "Return a specific HTTP status code (or a weighted random choice)",
        "description": "Returns the specified HTTP status code (200-599). 1xx codes return 400 with a JSON explanation: they are interim responses and cannot be sent as a final response. `200,500` picks uniformly, `200:0.9,500:0.1` by relative weight (up to 20 codes). Redirect codes (301, 302, 303, 307, 308) include `Location: /echo`; 401 adds WWW-Authenticate, 407 Proxy-Authenticate, 429 and 503 Retry-After. 204, 205 and 304 return empty bodies.",
        "operationId": "getStatus_patch",
        "parameters": [
          {
            "name": "code",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "pattern": "^[0-9]{3}(:[0-9.]+)?(,[0-9]{3}(:[0-9.]+)?)*$"
            },
            "example": "200:0.9,500:0.1",
            "description": "Status code, or comma-separated codes with optional :weight"
          }
        ],
        "responses": {
          "200": {
            "description": "Success response",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "status": {
                      "type": "integer"
                    },
                    "chosen_from": {
                      "type": "string"
                    }
                  }
                }
              },
              "application/xml": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "status": {
                      "type": "integer"
                    },
                    "chosen_from": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Invalid or informational (1xx) status code",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              },
              "application/xml": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          }
        }
      },
      "delete": {
        "tags": [
          "Status"
        ],
        "summary": "Return a specific HTTP status code (or a weighted random choice)",
        "description": "Returns the specified HTTP status code (200-599). 1xx codes return 400 with a JSON explanation: they are interim responses and cannot be sent as a final response. `200,500` picks uniformly, `200:0.9,500:0.1` by relative weight (up to 20 codes). Redirect codes (301, 302, 303, 307, 308) include `Location: /echo`; 401 adds WWW-Authenticate, 407 Proxy-Authenticate, 429 and 503 Retry-After. 204, 205 and 304 return empty bodies.",
        "operationId": "getStatus_delete",
        "parameters": [
          {
            "name": "code",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "pattern": "^[0-9]{3}(:[0-9.]+)?(,[0-9]{3}(:[0-9.]+)?)*$"
            },
            "example": "200:0.9,500:0.1",
            "description": "Status code, or comma-separated codes with optional :weight"
          }
        ],
        "responses": {
          "200": {
            "description": "Success response",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "status": {
                      "type": "integer"
                    },
                    "chosen_from": {
                      "type": "string"
                    }
                  }
                }
              },
              "application/xml": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "status": {
                      "type": "integer"
                    },
                    "chosen_from": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Invalid or informational (1xx) status code",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              },
              "application/xml": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          }
        }
      }
    },
    "/delay/{ms}": {
      "get": {
        "tags": [
          "Response Shaping"
        ],
        "summary": "Delay response by N milliseconds",
        "description": "Waits before responding. The value is milliseconds (`1500`), or carries a unit: `250ms`, `1.5s`. Maximum 60 s (10 s in public mode) including jitter; larger values return 400.",
        "operationId": "getDelay",
        "parameters": [
          {
            "name": "ms",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "pattern": "^[0-9.]+(ms|s)?$"
            },
            "example": "1500",
            "description": "Delay: milliseconds, or with an ms / s suffix"
          },
          {
            "name": "jitter",
            "in": "query",
            "required": false,
            "schema": {
              "type": "boolean"
            },
            "description": "Apply +-20% random jitter to the delay (capped at the maximum)"
          }
        ],
        "responses": {
          "200": {
            "description": "Delayed response with request details"
          },
          "400": {
            "description": "Invalid delay value",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              },
              "application/xml": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          }
        }
      },
      "post": {
        "tags": [
          "Response Shaping"
        ],
        "summary": "Delay response by N milliseconds",
        "description": "Waits before responding. The value is milliseconds (`1500`), or carries a unit: `250ms`, `1.5s`. Maximum 60 s (10 s in public mode) including jitter; larger values return 400.",
        "operationId": "getDelay_post",
        "parameters": [
          {
            "name": "ms",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "pattern": "^[0-9.]+(ms|s)?$"
            },
            "example": "1500",
            "description": "Delay: milliseconds, or with an ms / s suffix"
          },
          {
            "name": "jitter",
            "in": "query",
            "required": false,
            "schema": {
              "type": "boolean"
            },
            "description": "Apply +-20% random jitter to the delay (capped at the maximum)"
          }
        ],
        "responses": {
          "200": {
            "description": "Delayed response with request details"
          },
          "400": {
            "description": "Invalid delay value",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              },
              "application/xml": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          }
        }
      },
      "put": {
        "tags": [
          "Response Shaping"
        ],
        "summary": "Delay response by N milliseconds",
        "description": "Waits before responding. The value is milliseconds (`1500`), or carries a unit: `250ms`, `1.5s`. Maximum 60 s (10 s in public mode) including jitter; larger values return 400.",
        "operationId": "getDelay_put",
        "parameters": [
          {
            "name": "ms",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "pattern": "^[0-9.]+(ms|s)?$"
            },
            "example": "1500",
            "description": "Delay: milliseconds, or with an ms / s suffix"
          },
          {
            "name": "jitter",
            "in": "query",
            "required": false,
            "schema": {
              "type": "boolean"
            },
            "description": "Apply +-20% random jitter to the delay (capped at the maximum)"
          }
        ],
        "responses": {
          "200": {
            "description": "Delayed response with request details"
          },
          "400": {
            "description": "Invalid delay value",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              },
              "application/xml": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          }
        }
      },
      "patch": {
        "tags": [
          "Response Shaping"
        ],
        "summary": "Delay response by N milliseconds",
        "description": "Waits before responding. The value is milliseconds (`1500`), or carries a unit: `250ms`, `1.5s`. Maximum 60 s (10 s in public mode) including jitter; larger values return 400.",
        "operationId": "getDelay_patch",
        "parameters": [
          {
            "name": "ms",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "pattern": "^[0-9.]+(ms|s)?$"
            },
            "example": "1500",
            "description": "Delay: milliseconds, or with an ms / s suffix"
          },
          {
            "name": "jitter",
            "in": "query",
            "required": false,
            "schema": {
              "type": "boolean"
            },
            "description": "Apply +-20% random jitter to the delay (capped at the maximum)"
          }
        ],
        "responses": {
          "200": {
            "description": "Delayed response with request details"
          },
          "400": {
            "description": "Invalid delay value",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              },
              "application/xml": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          }
        }
      },
      "delete": {
        "tags": [
          "Response Shaping"
        ],
        "summary": "Delay response by N milliseconds",
        "description": "Waits before responding. The value is milliseconds (`1500`), or carries a unit: `250ms`, `1.5s`. Maximum 60 s (10 s in public mode) including jitter; larger values return 400.",
        "operationId": "getDelay_delete",
        "parameters": [
          {
            "name": "ms",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "pattern": "^[0-9.]+(ms|s)?$"
            },
            "example": "1500",
            "description": "Delay: milliseconds, or with an ms / s suffix"
          },
          {
            "name": "jitter",
            "in": "query",
            "required": false,
            "schema": {
              "type": "boolean"
            },
            "description": "Apply +-20% random jitter to the delay (capped at the maximum)"
          }
        ],
        "responses": {
          "200": {
            "description": "Delayed response with request details"
          },
          "400": {
            "description": "Invalid delay value",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              },
              "application/xml": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          }
        }
      }
    },
    "/response-headers": {
      "get": {
        "tags": [
          "Response Shaping"
        ],
        "summary": "Set arbitrary response headers",
        "description": "Any query parameters are set as response headers and returned in the JSON body (repeated names become several headers). Hop-by-hop and framing headers (Connection, Content-Length, Transfer-Encoding, Keep-Alive, TE, Trailer, Upgrade, ...) are refused with 400; Content-Type may be overridden.",
        "operationId": "getResponseHeaders",
        "parameters": [
          {
            "name": "X-Custom-Header",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Example: any query parameter becomes a response header"
          }
        ],
        "responses": {
          "200": {
            "description": "Response with custom headers"
          },
          "400": {
            "description": "Forbidden or invalid header",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              },
              "application/xml": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          }
        }
      }
    },
    "/cache/{ttl}": {
      "get": {
        "tags": [
          "Response Shaping"
        ],
        "summary": "Cacheable response with TTL",
        "description": "Returns a response with Cache-Control, ETag, Last-Modified and Vary: Accept. Conditional requests: If-None-Match (lists, weak tags, `*`; weak comparison) takes precedence over If-Modified-Since (second precision). JSON and XML representations have different ETags. 304 responses carry ETag, Cache-Control, Last-Modified and Vary.",
        "operationId": "getCache",
        "parameters": [
          {
            "name": "ttl",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer"
            },
            "description": "Cache TTL in seconds"
          },
          {
            "name": "If-None-Match",
            "in": "header",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "ETag for conditional request"
          },
          {
            "name": "If-Modified-Since",
            "in": "header",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Date for conditional request"
          }
        ],
        "responses": {
          "200": {
            "description": "Cacheable response with ETag and Cache-Control headers"
          },
          "304": {
            "description": "Not Modified - conditional request matched"
          }
        }
      }
    },
    "/redirect/{n}": {
      "get": {
        "tags": [
          "Redirects & Cookies"
        ],
        "summary": "Relative redirect chain",
        "description": "Performs N relative 302 redirects, ending at /echo. Max 20 hops.",
        "operationId": "getRedirect",
        "parameters": [
          {
            "name": "n",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 20
            },
            "description": "Number of redirects"
          }
        ],
        "responses": {
          "302": {
            "description": "Redirect",
            "headers": {
              "Location": {
                "schema": {
                  "type": "string"
                }
              }
            }
          },
          "400": {
            "description": "Invalid redirect count"
          }
        }
      }
    },
    "/cookies": {
      "get": {
        "tags": [
          "Redirects & Cookies"
        ],
        "summary": "Get cookies",
        "description": "Returns all cookies sent with the request.",
        "operationId": "getCookies",
        "responses": {
          "200": {
            "description": "Cookies from the request",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "cookies": {
                      "type": "object",
                      "additionalProperties": {
                        "type": "string"
                      }
                    }
                  }
                }
              },
              "application/xml": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "cookies": {
                      "type": "object",
                      "additionalProperties": {
                        "type": "string"
                      }
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/cookies/set": {
      "get": {
        "tags": [
          "Redirects & Cookies"
        ],
        "summary": "Set cookies via query parameters",
        "description": "Sets cookies from query parameters and redirects to /cookies. Use _path (default /), _domain, _secure, _httponly, _samesite (Strict, Lax, None; None forces Secure), _maxage for cookie options. Names must be RFC 6265 tokens; values are percent-encoded where they contain characters outside cookie-octet (space, ;, comma, quotes, CR/LF, non-ASCII).",
        "operationId": "setCookies",
        "parameters": [
          {
            "name": "name",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Cookie name=value (any query param becomes a cookie)"
          },
          {
            "name": "_path",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "default": "/"
            },
            "description": "Cookie Path attribute"
          },
          {
            "name": "_domain",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Cookie Domain attribute"
          },
          {
            "name": "_secure",
            "in": "query",
            "required": false,
            "schema": {
              "type": "boolean"
            },
            "description": "Cookie Secure flag"
          },
          {
            "name": "_httponly",
            "in": "query",
            "required": false,
            "schema": {
              "type": "boolean"
            },
            "description": "Cookie HttpOnly flag"
          },
          {
            "name": "_samesite",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "enum": [
                "Strict",
                "Lax",
                "None"
              ]
            },
            "description": "Cookie SameSite attribute"
          },
          {
            "name": "_maxage",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer"
            },
            "description": "Cookie Max-Age in seconds"
          }
        ],
        "responses": {
          "302": {
            "description": "Redirect to /cookies with Set-Cookie headers"
          },
          "400": {
            "description": "Invalid cookie name or attribute",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              },
              "application/xml": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          }
        }
      }
    },
    "/cookies/set/{name}/{value}": {
      "get": {
        "tags": [
          "Redirects & Cookies"
        ],
        "summary": "Set a single cookie",
        "description": "Sets a single cookie with the given name and value, then redirects to /cookies.",
        "operationId": "setCookie",
        "parameters": [
          {
            "name": "name",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Cookie name"
          },
          {
            "name": "value",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Cookie value"
          }
        ],
        "responses": {
          "302": {
            "description": "Redirect to /cookies with Set-Cookie header"
          }
        }
      }
    },
    "/cookies/delete": {
      "get": {
        "tags": [
          "Redirects & Cookies"
        ],
        "summary": "Delete cookies",
        "description": "Deletes cookies named in the query parameters by setting Max-Age=0 and an expired Expires, with Path (default /) and Domain matching how they were set (_path, _domain).",
        "operationId": "deleteCookies",
        "parameters": [
          {
            "name": "name",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Cookie name to delete (any query param name)"
          },
          {
            "name": "_path",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "default": "/"
            },
            "description": "Path the cookie was set with"
          },
          {
            "name": "_domain",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Domain the cookie was set with"
          }
        ],
        "responses": {
          "302": {
            "description": "Redirect to /cookies with expired Set-Cookie headers"
          }
        }
      }
    },
    "/ip": {
      "get": {
        "tags": [
          "Info"
        ],
        "summary": "Client IP address",
        "description": "Returns the client's IP address. Respects X-Forwarded-For when RUSTYBIN_TRUST_FORWARD=true.",
        "operationId": "getIp",
        "responses": {
          "200": {
            "description": "IP address",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "ipv4": {
                      "type": "string",
                      "example": "127.0.0.1",
                      "nullable": true
                    },
                    "ipv6": {
                      "type": "string",
                      "nullable": true
                    }
                  }
                }
              },
              "application/xml": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "ipv4": {
                      "type": "string",
                      "example": "127.0.0.1",
                      "nullable": true
                    },
                    "ipv6": {
                      "type": "string",
                      "nullable": true
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/ip/v4": {
      "get": {
        "tags": [
          "Info"
        ],
        "summary": "Client IPv4 address",
        "operationId": "getIpV4",
        "responses": {
          "200": {
            "description": "IPv4 address"
          }
        }
      }
    },
    "/ip/v6": {
      "get": {
        "tags": [
          "Info"
        ],
        "summary": "Client IPv6 address",
        "operationId": "getIpV6",
        "responses": {
          "200": {
            "description": "IPv6 address"
          }
        }
      }
    },
    "/date": {
      "get": {
        "tags": [
          "Info"
        ],
        "summary": "Current date (UTC)",
        "description": "Returns the current date in UTC.",
        "operationId": "getDate",
        "responses": {
          "200": {
            "description": "Date",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "date": {
                      "type": "string",
                      "format": "date",
                      "example": "2024-01-01"
                    },
                    "timezone": {
                      "type": "string",
                      "example": "UTC"
                    }
                  }
                }
              },
              "application/xml": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "date": {
                      "type": "string",
                      "format": "date",
                      "example": "2024-01-01"
                    },
                    "timezone": {
                      "type": "string",
                      "example": "UTC"
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/date/{timezone}": {
      "get": {
        "tags": [
          "Info"
        ],
        "summary": "Current date in timezone",
        "operationId": "getDateTz",
        "parameters": [
          {
            "name": "timezone",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "example": "America/New_York",
            "description": "IANA timezone name"
          }
        ],
        "responses": {
          "200": {
            "description": "Date in timezone"
          },
          "404": {
            "description": "Unknown timezone"
          }
        }
      }
    },
    "/time": {
      "get": {
        "tags": [
          "Info"
        ],
        "summary": "Current time (UTC)",
        "description": "Returns the current date and time in UTC (RFC 3339).",
        "operationId": "getTime",
        "responses": {
          "200": {
            "description": "Time",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "time": {
                      "type": "string",
                      "format": "date-time"
                    },
                    "timezone": {
                      "type": "string",
                      "example": "UTC"
                    }
                  }
                }
              },
              "application/xml": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "time": {
                      "type": "string",
                      "format": "date-time"
                    },
                    "timezone": {
                      "type": "string",
                      "example": "UTC"
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/time/{timezone}": {
      "get": {
        "tags": [
          "Info"
        ],
        "summary": "Current time in timezone",
        "operationId": "getTimeTz",
        "parameters": [
          {
            "name": "timezone",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "example": "Europe/London",
            "description": "IANA timezone name"
          }
        ],
        "responses": {
          "200": {
            "description": "Time in timezone"
          },
          "404": {
            "description": "Unknown timezone"
          }
        }
      }
    },
    "/uuid": {
      "get": {
        "tags": [
          "Random"
        ],
        "summary": "Generate a UUID v4",
        "operationId": "getUuid",
        "responses": {
          "200": {
            "description": "UUID",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "uuid": {
                      "type": "string",
                      "format": "uuid"
                    }
                  }
                }
              },
              "application/xml": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "uuid": {
                      "type": "string",
                      "format": "uuid"
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/guuid": {
      "get": {
        "tags": [
          "Random"
        ],
        "summary": "Generate a GUID (braced UUID)",
        "operationId": "getGuuid",
        "responses": {
          "200": {
            "description": "GUID",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "guuid": {
                      "type": "string",
                      "example": "{550e8400-e29b-41d4-a716-446655440000}"
                    }
                  }
                }
              },
              "application/xml": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "guuid": {
                      "type": "string",
                      "example": "{550e8400-e29b-41d4-a716-446655440000}"
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/random": {
      "get": {
        "tags": [
          "Random"
        ],
        "summary": "Random data bundle",
        "description": "Returns random int, uint, uuid, guuid, and lorem ipsum text.",
        "operationId": "getRandom",
        "responses": {
          "200": {
            "description": "Random data"
          }
        }
      }
    },
    "/random/int": {
      "get": {
        "tags": [
          "Random"
        ],
        "summary": "Random integer (-32000 to 32000)",
        "operationId": "getRandomInt",
        "responses": {
          "200": {
            "description": "Random integer",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "value": {
                      "type": "integer"
                    }
                  }
                }
              },
              "application/xml": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "value": {
                      "type": "integer"
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/random/int/{lower}/{upper}": {
      "get": {
        "tags": [
          "Random"
        ],
        "summary": "Random integer in range",
        "operationId": "getRandomIntRange",
        "parameters": [
          {
            "name": "lower",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer"
            },
            "description": "Lower bound (inclusive)"
          },
          {
            "name": "upper",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer"
            },
            "description": "Upper bound (inclusive)"
          }
        ],
        "responses": {
          "200": {
            "description": "Random integer in range"
          },
          "400": {
            "description": "Invalid range (lower >= upper)"
          }
        }
      }
    },
    "/random/uint": {
      "get": {
        "tags": [
          "Random"
        ],
        "summary": "Random unsigned integer (0-65535)",
        "operationId": "getRandomUint",
        "responses": {
          "200": {
            "description": "Random unsigned integer"
          }
        }
      }
    },
    "/random/lorem-ipsum": {
      "get": {
        "tags": [
          "Random"
        ],
        "summary": "Lorem ipsum text (1 paragraph)",
        "operationId": "getLoremIpsum",
        "responses": {
          "200": {
            "description": "Lorem ipsum paragraph(s)",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "paragraphs": {
                      "type": "array",
                      "items": {
                        "type": "string"
                      }
                    }
                  }
                }
              },
              "application/xml": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "paragraphs": {
                      "type": "array",
                      "items": {
                        "type": "string"
                      }
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/random/lorem-ipsum/{count}": {
      "get": {
        "tags": [
          "Random"
        ],
        "summary": "Lorem ipsum text (N paragraphs)",
        "operationId": "getLoremIpsumCount",
        "parameters": [
          {
            "name": "count",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 32
            },
            "description": "Number of paragraphs"
          }
        ],
        "responses": {
          "200": {
            "description": "Lorem ipsum paragraphs"
          },
          "400": {
            "description": "Invalid count"
          }
        }
      }
    },
    "/graphql": {
      "get": {
        "tags": [
          "GraphQL"
        ],
        "summary": "GraphQL query over GET (or GraphiQL for browsers)",
        "description": "Runs `query` (with optional `variables` / `operationName` / `extensions` as JSON strings). Mutations over GET return 405. Without a query, `Accept: text/html` gets a GraphiQL page (pinned CDN versions); other clients get 400.",
        "operationId": "getGraphql",
        "parameters": [
          {
            "name": "query",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "example": "{ users { id name } }"
          },
          {
            "name": "variables",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "JSON object"
          },
          {
            "name": "operationName",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "extensions",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "JSON object, e.g. persistedQuery"
          }
        ],
        "responses": {
          "200": {
            "description": "GraphQL response, or the GraphiQL page",
            "content": {
              "application/json": {},
              "application/graphql-response+json": {},
              "text/html": {}
            }
          },
          "400": {
            "description": "Request error (and parse/validation errors with application/graphql-response+json)"
          },
          "405": {
            "description": "Mutation over GET"
          }
        }
      },
      "post": {
        "tags": [
          "GraphQL"
        ],
        "summary": "Execute GraphQL query",
        "description": "Executes a GraphQL operation against the hardcoded dataset (users, products, orders, reviews). Content-Type application/json (or application/graphql with the query as body; others 415). `Accept: application/graphql-response+json` enables GraphQL-over-HTTP status codes (400 for parse/validation/limit errors); legacy application/json answers 200 for well-formed requests. Limits: depth 10, complexity 500, 30 aliases. Automatic persisted queries via extensions.persistedQuery (version 1, sha256Hash); unknown hashes return PersistedQueryNotFound.",
        "operationId": "postGraphql",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "query": {
                    "type": "string",
                    "example": "{ users { id name email } }"
                  },
                  "variables": {
                    "type": "object"
                  },
                  "operationName": {
                    "type": "string"
                  },
                  "extensions": {
                    "type": "object",
                    "properties": {
                      "persistedQuery": {
                        "type": "object",
                        "properties": {
                          "version": {
                            "type": "integer",
                            "example": 1
                          },
                          "sha256Hash": {
                            "type": "string"
                          }
                        }
                      }
                    }
                  }
                }
              }
            },
            "application/graphql": {
              "schema": {
                "type": "string"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "GraphQL response",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "type": "object"
                    },
                    "errors": {
                      "type": "array",
                      "items": {
                        "type": "object"
                      }
                    }
                  }
                }
              },
              "application/graphql-response+json": {}
            }
          },
          "400": {
            "description": "Malformed request (or document error with application/graphql-response+json)"
          },
          "415": {
            "description": "Unsupported Content-Type"
          }
        }
      }
    },
    "/graphql/schema": {
      "get": {
        "tags": [
          "GraphQL"
        ],
        "summary": "GraphQL SDL schema",
        "description": "Returns the GraphQL schema in SDL format.",
        "operationId": "getGraphqlSchema",
        "responses": {
          "200": {
            "description": "GraphQL SDL",
            "content": {
              "text/plain": {
                "schema": {
                  "type": "string"
                }
              }
            }
          }
        }
      }
    },
    "/orchestration/step/1": {
      "post": {
        "tags": [
          "Orchestration"
        ],
        "summary": "Step 1: authenticate",
        "description": "Validate API key and return merchant metadata with correlation token",
        "operationId": "postOrchestrationStep1",
        "parameters": [
          {
            "name": "X-Api-Key",
            "in": "header",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "API key (any non-empty value)"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Step 1 result"
          },
          "400": {
            "description": "Missing required headers or body fields"
          },
          "401": {
            "description": "Missing API key (step 1 only)"
          },
          "403": {
            "description": "Validation not approved (step 4 only)"
          }
        }
      }
    },
    "/orchestration/step/2": {
      "post": {
        "tags": [
          "Orchestration"
        ],
        "summary": "Step 2: enrich",
        "description": "Enrich the transaction with a deterministic risk score (0-99, stable hash of correlation id, merchant_id, amount and card BIN) and card details. Amounts are numbers in major units (99.99).",
        "operationId": "postOrchestrationStep2",
        "parameters": [
          {
            "name": "X-Correlation-Id",
            "in": "header",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Correlation ID from step 1"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Step 2 result"
          },
          "400": {
            "description": "Missing required headers or body fields"
          },
          "401": {
            "description": "Missing API key (step 1 only)"
          },
          "403": {
            "description": "Validation not approved (step 4 only)"
          }
        }
      }
    },
    "/orchestration/step/3": {
      "post": {
        "tags": [
          "Orchestration"
        ],
        "summary": "Step 3: validate",
        "description": "Apply business rules: declined when the risk score (forwarded `risk_score`, else computed like step 2) is >= 70, the amount exceeds 50000 or card_payment is not permitted. validation.result is the X-Validation-Result value for step 4.",
        "operationId": "postOrchestrationStep3",
        "parameters": [
          {
            "name": "X-Correlation-Id",
            "in": "header",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Correlation ID from step 1"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Step 3 result"
          },
          "400": {
            "description": "Missing required headers or body fields"
          },
          "401": {
            "description": "Missing API key (step 1 only)"
          },
          "403": {
            "description": "Validation not approved (step 4 only)"
          }
        }
      }
    },
    "/orchestration/step/4": {
      "post": {
        "tags": [
          "Orchestration"
        ],
        "summary": "Step 4: process",
        "description": "Execute the payment and return transaction result",
        "operationId": "postOrchestrationStep4",
        "parameters": [
          {
            "name": "X-Correlation-Id",
            "in": "header",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Correlation ID from step 1"
          },
          {
            "name": "X-Validation-Result",
            "in": "header",
            "required": true,
            "schema": {
              "type": "string",
              "enum": [
                "approved"
              ]
            },
            "description": "Must be 'approved'"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Step 4 result"
          },
          "400": {
            "description": "Missing required headers or body fields"
          },
          "401": {
            "description": "Missing API key (step 1 only)"
          },
          "403": {
            "description": "Validation not approved (step 4 only)"
          }
        }
      }
    },
    "/orchestration/status": {
      "get": {
        "tags": [
          "Orchestration"
        ],
        "summary": "Orchestration pipeline overview",
        "description": "Returns documentation of all orchestration steps with required headers and example bodies.",
        "operationId": "getOrchestrationStatus",
        "responses": {
          "200": {
            "description": "Pipeline documentation"
          }
        }
      }
    },
    "/soap": {
      "get": {
        "tags": [
          "SOAP"
        ],
        "summary": "WSDL (GET /soap?wsdl)",
        "description": "With the `wsdl` query string returns the WSDL document; otherwise 405 with a SOAP fault.",
        "operationId": "getSoapWsdlQuery",
        "responses": {
          "200": {
            "description": "WSDL document",
            "content": {
              "text/xml": {
                "schema": {
                  "type": "string"
                }
              }
            }
          },
          "405": {
            "description": "Use POST for SOAP calls"
          }
        }
      },
      "post": {
        "tags": [
          "SOAP"
        ],
        "summary": "SOAP 1.1 / 1.2 web service",
        "description": "Accepts SOAP 1.1 (text/xml, envelope http://schemas.xmlsoap.org/soap/envelope/) and SOAP 1.2 (application/soap+xml, envelope http://www.w3.org/2003/05/soap-envelope) and responds in kind. Operations: GetUser, CreateOrder, GetStatus, dispatched by SOAPAction (1.1) or the Content-Type action parameter (1.2), falling back to the first Body element. Faults: SOAP 1.1 faultcode/faultstring/detail with HTTP 500; SOAP 1.2 Code/Reason/Detail with HTTP 400 (env:Sender) or 500.",
        "operationId": "postSoap",
        "parameters": [
          {
            "name": "SOAPAction",
            "in": "header",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "SOAP 1.1 action URI, e.g. \"http://rustybin.local/GetUser\""
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "text/xml": {
              "schema": {
                "type": "string"
              },
              "example": "<soap:Envelope xmlns:soap=\"http://schemas.xmlsoap.org/soap/envelope/\"><soap:Body><GetUser xmlns=\"http://rustybin.local/users\"><userId>123</userId></GetUser></soap:Body></soap:Envelope>"
            },
            "application/soap+xml": {
              "schema": {
                "type": "string"
              },
              "example": "<env:Envelope xmlns:env=\"http://www.w3.org/2003/05/soap-envelope\"><env:Body><GetStatus xmlns=\"http://rustybin.local/status\"><orderId>ORD-1</orderId></GetStatus></env:Body></env:Envelope>"
            }
          }
        },
        "responses": {
          "200": {
            "description": "SOAP response",
            "content": {
              "text/xml": {
                "schema": {
                  "type": "string"
                }
              },
              "application/soap+xml": {
                "schema": {
                  "type": "string"
                }
              }
            }
          },
          "400": {
            "description": "SOAP 1.2 sender fault",
            "content": {
              "application/soap+xml": {
                "schema": {
                  "type": "string"
                }
              }
            }
          },
          "500": {
            "description": "SOAP fault (1.1: every fault; 1.2: receiver, version mismatch, mustUnderstand)",
            "content": {
              "text/xml": {
                "schema": {
                  "type": "string"
                }
              },
              "application/soap+xml": {
                "schema": {
                  "type": "string"
                }
              }
            }
          }
        }
      }
    },
    "/soap/wsdl": {
      "get": {
        "tags": [
          "SOAP"
        ],
        "summary": "WSDL service description",
        "description": "Returns the WSDL document defining the SOAP service operations (GetUser, CreateOrder, GetStatus) with SOAP 1.1 and SOAP 1.2 bindings; soap:address is derived from the request (Host, or trusted X-Forwarded-* headers).",
        "operationId": "getSoapWsdl",
        "responses": {
          "200": {
            "description": "WSDL document",
            "content": {
              "text/xml": {
                "schema": {
                  "type": "string"
                }
              }
            }
          }
        }
      }
    },
    "/_rustybin/requests": {
      "get": {
        "tags": [
          "Control Plane"
        ],
        "summary": "List captured requests",
        "operationId": "listCapturedRequests",
        "parameters": [
          {
            "name": "session",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Only entries captured with this X-Rustybin-Session value (required in public mode)"
          },
          {
            "name": "path_prefix",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "default": 100
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Captured requests, newest first",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "count": {
                      "type": "integer"
                    },
                    "capacity": {
                      "type": "integer"
                    },
                    "public_mode": {
                      "type": "boolean"
                    },
                    "requests": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/CapturedRequest"
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Missing ?session= in public mode"
          },
          "403": {
            "description": "permission_required: the caller lacks traffic.read"
          }
        },
        "x-rustybin-permission": "traffic.read"
      },
      "delete": {
        "tags": [
          "Control Plane"
        ],
        "summary": "Clear captured requests",
        "description": "With ?session= clears that session only; otherwise requires the admin token.",
        "operationId": "clearCapturedRequests",
        "parameters": [
          {
            "name": "session",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Only entries captured with this X-Rustybin-Session value (required in public mode)"
          }
        ],
        "responses": {
          "200": {
            "description": "Number of cleared entries"
          },
          "401": {
            "description": "Admin token required"
          },
          "403": {
            "description": "Disabled in public mode without an admin token"
          }
        },
        "x-rustybin-permission": "traffic.read"
      }
    },
    "/_rustybin/requests/stream": {
      "get": {
        "tags": [
          "Control Plane"
        ],
        "summary": "Live captured-request feed (SSE)",
        "operationId": "streamCapturedRequests",
        "parameters": [
          {
            "name": "session",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Only entries captured with this X-Rustybin-Session value (required in public mode)"
          },
          {
            "name": "path_prefix",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "text/event-stream of `request` events",
            "content": {
              "text/event-stream": {}
            }
          },
          "403": {
            "description": "permission_required: the caller lacks traffic.read"
          }
        },
        "x-rustybin-permission": "traffic.read"
      }
    },
    "/_rustybin/requests/{id}": {
      "get": {
        "tags": [
          "Control Plane"
        ],
        "summary": "Get one captured request",
        "operationId": "getCapturedRequest",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "session",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Only entries captured with this X-Rustybin-Session value (required in public mode)"
          }
        ],
        "responses": {
          "200": {
            "description": "Captured request",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CapturedRequest"
                }
              }
            }
          },
          "404": {
            "description": "Unknown id (or not visible to this session)"
          },
          "403": {
            "description": "permission_required: the caller lacks traffic.read"
          }
        },
        "x-rustybin-permission": "traffic.read"
      }
    },
    "/_rustybin/audit": {
      "get": {
        "tags": [
          "Control Plane"
        ],
        "summary": "The audit log",
        "operationId": "listAudit",
        "parameters": [
          {
            "name": "actor",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Contained in the actor's kind, user id, name or agent (any case)"
          },
          {
            "name": "action",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Contained in the action (route template and method, or tool) or the event"
          },
          {
            "name": "target",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Contained in a target's name; kind:name for one kind (mock:petstore)"
          },
          {
            "name": "since",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "RFC 3339, a UTC day (2026-11-03) or an age (15m, 2h, 7d)"
          },
          {
            "name": "until",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "RFC 3339, a UTC day or an age"
          },
          {
            "name": "result",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "ok, error, refused, asked, or a status code"
          },
          {
            "name": "cursor",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "The next_cursor of the previous page"
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 500,
              "default": 100
            }
          }
        ],
        "responses": {
          "200": {
            "description": "{entries (newest first), next_cursor, log: held, capacity, persisted, files, bytes, retention_days, max_bytes, not_written, suppressed}"
          },
          "400": {
            "description": "An invalid filter"
          },
          "403": {
            "description": "permission_required: audit.read"
          }
        },
        "x-rustybin-permission": "audit.read"
      }
    },
    "/_rustybin/audit/stream": {
      "get": {
        "tags": [
          "Control Plane"
        ],
        "summary": "Live tail of the audit log (SSE)",
        "operationId": "streamAudit",
        "parameters": [
          {
            "name": "actor",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Contained in the actor's kind, user id, name or agent (any case)"
          },
          {
            "name": "action",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Contained in the action (route template and method, or tool) or the event"
          },
          {
            "name": "target",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Contained in a target's name; kind:name for one kind (mock:petstore)"
          },
          {
            "name": "since",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "RFC 3339, a UTC day (2026-11-03) or an age (15m, 2h, 7d)"
          },
          {
            "name": "until",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "RFC 3339, a UTC day or an age"
          },
          {
            "name": "result",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "ok, error, refused, asked, or a status code"
          }
        ],
        "responses": {
          "200": {
            "description": "text/event-stream: entry events"
          },
          "400": {
            "description": "An invalid filter"
          },
          "403": {
            "description": "permission_required: audit.read"
          },
          "429": {
            "description": "Too many listeners"
          }
        },
        "x-rustybin-permission": "audit.read"
      }
    },
    "/_rustybin/mcp": {
      "post": {
        "tags": [
          "Control Plane"
        ],
        "summary": "Management MCP: send a JSON-RPC message (tools/list, tools/call, ...)",
        "operationId": "manageMcpPost",
        "parameters": [
          {
            "name": "MCP-Protocol-Version",
            "in": "header",
            "required": false,
            "schema": {
              "type": "string",
              "example": "2026-07-28"
            }
          },
          {
            "name": "Mcp-Method",
            "in": "header",
            "required": false,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "Mcp-Name",
            "in": "header",
            "required": false,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "Mcp-Session-Id",
            "in": "header",
            "required": false,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "JSON-RPC response (application/json) or SSE stream (text/event-stream)",
            "content": {
              "application/json": {},
              "text/event-stream": {}
            }
          },
          "202": {
            "description": "Notification accepted"
          },
          "400": {
            "description": "Invalid message or missing session"
          },
          "401": {
            "description": "Control-plane credentials required"
          },
          "403": {
            "description": "Origin not allowed"
          },
          "404": {
            "description": "Unknown method or session"
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/McpJsonRpcMessage"
              }
            }
          }
        },
        "x-rustybin-permission": "signed in"
      },
      "get": {
        "tags": [
          "Control Plane"
        ],
        "summary": "Management MCP: open the server-to-client stream (2025-xx sessions)",
        "operationId": "manageMcpStream",
        "parameters": [
          {
            "name": "MCP-Protocol-Version",
            "in": "header",
            "required": false,
            "schema": {
              "type": "string",
              "example": "2026-07-28"
            }
          },
          {
            "name": "Mcp-Method",
            "in": "header",
            "required": false,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "Mcp-Name",
            "in": "header",
            "required": false,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "Mcp-Session-Id",
            "in": "header",
            "required": false,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "JSON-RPC response (application/json) or SSE stream (text/event-stream)",
            "content": {
              "application/json": {},
              "text/event-stream": {}
            }
          },
          "202": {
            "description": "Notification accepted"
          },
          "400": {
            "description": "Invalid message or missing session"
          },
          "401": {
            "description": "Control-plane credentials required"
          },
          "403": {
            "description": "Origin not allowed"
          },
          "404": {
            "description": "Unknown method or session"
          }
        },
        "x-rustybin-permission": "signed in"
      },
      "delete": {
        "tags": [
          "Control Plane"
        ],
        "summary": "Management MCP: terminate the session (2025-xx)",
        "operationId": "manageMcpDelete",
        "parameters": [
          {
            "name": "MCP-Protocol-Version",
            "in": "header",
            "required": false,
            "schema": {
              "type": "string",
              "example": "2026-07-28"
            }
          },
          {
            "name": "Mcp-Method",
            "in": "header",
            "required": false,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "Mcp-Name",
            "in": "header",
            "required": false,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "Mcp-Session-Id",
            "in": "header",
            "required": false,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "JSON-RPC response (application/json) or SSE stream (text/event-stream)",
            "content": {
              "application/json": {},
              "text/event-stream": {}
            }
          },
          "202": {
            "description": "Notification accepted"
          },
          "400": {
            "description": "Invalid message or missing session"
          },
          "401": {
            "description": "Control-plane credentials required"
          },
          "403": {
            "description": "Origin not allowed"
          },
          "404": {
            "description": "Unknown method or session"
          }
        },
        "x-rustybin-permission": "signed in"
      }
    },
    "/_rustybin/agents": {
      "get": {
        "tags": [
          "Control Plane"
        ],
        "summary": "AI agents on the management MCP server",
        "operationId": "listAgents",
        "parameters": [
          {
            "name": "owner",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Only the agents acting for this user (an id or a sign-in name)"
          }
        ],
        "responses": {
          "200": {
            "description": "{agents (each with owner and owner_label), owner, policy, capacity, persisted}"
          },
          "403": {
            "description": "permission_required: agents.read (another user's agent) or agents.manage (changing another user's agent, or widening your own)"
          }
        },
        "x-rustybin-permission": "signed in"
      }
    },
    "/_rustybin/agents/events": {
      "get": {
        "tags": [
          "Control Plane"
        ],
        "summary": "Live feed of agent calls (SSE)",
        "operationId": "streamAgentEvents",
        "responses": {
          "200": {
            "description": "text/event-stream: call and agent events"
          },
          "403": {
            "description": "permission_required: agents.read (another user's agent) or agents.manage (changing another user's agent, or widening your own)"
          },
          "429": {
            "description": "Too many listeners"
          }
        },
        "x-rustybin-permission": "signed in"
      }
    },
    "/_rustybin/agents/{id}": {
      "get": {
        "tags": [
          "Control Plane"
        ],
        "summary": "One AI agent",
        "operationId": "getAgent",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "The agent with owner, tools, last_errors, sessions, override and available_tools"
          },
          "403": {
            "description": "permission_required: agents.read (another user's agent) or agents.manage (changing another user's agent, or widening your own)"
          },
          "404": {
            "description": "No such agent"
          }
        },
        "x-rustybin-permission": "signed in"
      },
      "patch": {
        "tags": [
          "Control Plane"
        ],
        "summary": "Set an AI agent's rights and note",
        "operationId": "setAgentRights",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "additionalProperties": false,
                "properties": {
                  "rights": {
                    "type": [
                      "object",
                      "null"
                    ],
                    "additionalProperties": false,
                    "properties": {
                      "ceiling": {
                        "type": "string",
                        "description": "read-only, traffic, manage, full, or a role name"
                      },
                      "allow": {
                        "type": "array",
                        "items": {
                          "type": "string"
                        },
                        "description": "Management tool names"
                      },
                      "deny": {
                        "type": "array",
                        "items": {
                          "type": "string"
                        },
                        "description": "Management tool names"
                      }
                    }
                  },
                  "note": {
                    "type": [
                      "string",
                      "null"
                    ],
                    "maxLength": 500
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The agent"
          },
          "400": {
            "description": "Invalid rights (an unknown tool or role)"
          },
          "403": {
            "description": "permission_required: agents.read (another user's agent) or agents.manage (changing another user's agent, or widening your own)"
          },
          "404": {
            "description": "No such agent"
          }
        },
        "x-rustybin-permission": "signed in"
      }
    },
    "/_rustybin/agents/{id}/revoke": {
      "post": {
        "tags": [
          "Control Plane"
        ],
        "summary": "Revoke an AI agent",
        "operationId": "revokeAgent",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "{revoked, sessions_ended, tokens_revoked, note}"
          },
          "403": {
            "description": "permission_required: agents.read (another user's agent) or agents.manage (changing another user's agent, or widening your own)"
          },
          "404": {
            "description": "No such agent"
          }
        },
        "x-rustybin-permission": "signed in"
      }
    },
    "/_rustybin/agents/{id}/restore": {
      "post": {
        "tags": [
          "Control Plane"
        ],
        "summary": "Restore a revoked AI agent",
        "operationId": "restoreAgent",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "{restored}"
          },
          "403": {
            "description": "permission_required: agents.read (another user's agent) or agents.manage (changing another user's agent, or widening your own)"
          },
          "404": {
            "description": "No such agent"
          }
        },
        "x-rustybin-permission": "signed in"
      }
    },
    "/_rustybin/agents/{id}/sessions": {
      "delete": {
        "tags": [
          "Control Plane"
        ],
        "summary": "End an AI agent's MCP sessions",
        "operationId": "endAgentSessions",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "{sessions_ended}"
          },
          "403": {
            "description": "permission_required: agents.read (another user's agent) or agents.manage (changing another user's agent, or widening your own)"
          },
          "404": {
            "description": "No such agent"
          }
        },
        "x-rustybin-permission": "signed in"
      }
    },
    "/_rustybin/config/export": {
      "get": {
        "tags": [
          "Control Plane"
        ],
        "summary": "The whole instance as rustybin.yaml",
        "operationId": "exportConfig",
        "parameters": [
          {
            "name": "format",
            "in": "query",
            "schema": {
              "type": "string",
              "enum": [
                "yaml",
                "json",
                "bundle"
              ],
              "default": "yaml"
            }
          },
          {
            "name": "secrets",
            "in": "query",
            "schema": {
              "type": "string",
              "enum": [
                "refs",
                "omit"
              ],
              "default": "refs"
            },
            "description": "refs: ${VAR} and secret:stored references; omit: no secrets section, demo credentials redacted"
          }
        ],
        "responses": {
          "200": {
            "description": "The document (application/yaml or application/json) or the bundle (application/gzip)"
          },
          "401": {
            "description": "Admin rights required"
          },
          "403": {
            "description": "permission_required: the caller lacks config.export"
          }
        },
        "x-rustybin-permission": "config.export"
      }
    },
    "/_rustybin/config/apply": {
      "post": {
        "tags": [
          "Control Plane"
        ],
        "summary": "Apply a rustybin.yaml document",
        "operationId": "applyConfig",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "document"
                ],
                "additionalProperties": false,
                "properties": {
                  "document": {
                    "description": "The document: YAML or JSON text, or a JSON object",
                    "oneOf": [
                      {
                        "type": "string"
                      },
                      {
                        "type": "object"
                      }
                    ]
                  },
                  "prune": {
                    "type": "boolean",
                    "default": false,
                    "description": "A present section is the whole truth for its part of the instance"
                  },
                  "dry_run": {
                    "type": "boolean",
                    "default": false
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "{ok, dry_run, prune, sections, changes, summary, results, problems}"
          },
          "400": {
            "description": "Not a document"
          },
          "401": {
            "description": "Admin rights required"
          },
          "403": {
            "description": "permission_required: the caller lacks config.apply"
          }
        },
        "x-rustybin-permission": "config.apply"
      }
    },
    "/_rustybin/config/schema": {
      "get": {
        "tags": [
          "Control Plane"
        ],
        "summary": "JSON Schema of rustybin.yaml",
        "operationId": "getConfigSchema",
        "responses": {
          "200": {
            "description": "The schema (application/schema+json)"
          },
          "403": {
            "description": "permission_required: the caller lacks instance.read"
          }
        },
        "x-rustybin-permission": "instance.read"
      }
    },
    "/_rustybin/git": {
      "get": {
        "tags": [
          "Control Plane"
        ],
        "summary": "Source control status",
        "operationId": "gitStatus",
        "parameters": [
          {
            "name": "fetch",
            "in": "query",
            "schema": {
              "type": "boolean"
            },
            "description": "Ask the remote for ahead and behind"
          }
        ],
        "responses": {
          "200": {
            "description": "{git, remote, branch, path, auth, initialised, head, ahead, behind, drift, deploy_key, timeline}"
          },
          "401": {
            "description": "Admin rights required"
          },
          "403": {
            "description": "permission_required: the caller lacks git.read"
          }
        },
        "x-rustybin-permission": "git.read"
      }
    },
    "/_rustybin/git/init": {
      "post": {
        "tags": [
          "Control Plane"
        ],
        "summary": "Connect the repository",
        "operationId": "gitInit",
        "responses": {
          "200": {
            "description": "{initialised, fresh, remote_branch, head}"
          },
          "401": {
            "description": "Admin rights required"
          },
          "409": {
            "description": "Not configured, not initialised, busy, or a conflict to resolve"
          },
          "502": {
            "description": "git failed (the remote, the network)"
          },
          "403": {
            "description": "permission_required: the caller lacks git.write"
          }
        },
        "x-rustybin-permission": "git.write"
      }
    },
    "/_rustybin/git/commit": {
      "post": {
        "tags": [
          "Control Plane"
        ],
        "summary": "Commit the instance's configuration",
        "operationId": "gitCommit",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "message"
                ],
                "properties": {
                  "message": {
                    "type": "string",
                    "maxLength": 2000
                  },
                  "checkpoints": {
                    "type": "array",
                    "items": {
                      "type": "string"
                    },
                    "maxItems": 20,
                    "default": [],
                    "description": "Local checkpoints written to <git.path>/checkpoints/<name>.json in this commit (mock data: an explicit commit only)"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "{committed, files, checkpoints, head}"
          },
          "401": {
            "description": "Admin rights required"
          },
          "409": {
            "description": "Not configured, not initialised, busy, or a conflict to resolve"
          },
          "502": {
            "description": "git failed (the remote, the network)"
          },
          "403": {
            "description": "permission_required: the caller lacks git.write"
          }
        },
        "x-rustybin-permission": "git.write"
      }
    },
    "/_rustybin/git/push": {
      "post": {
        "tags": [
          "Control Plane"
        ],
        "summary": "Push",
        "operationId": "gitPush",
        "responses": {
          "200": {
            "description": "{pushed, head}"
          },
          "401": {
            "description": "Admin rights required"
          },
          "409": {
            "description": "Not configured, not initialised, busy, or a conflict to resolve"
          },
          "502": {
            "description": "git failed (the remote, the network)"
          },
          "403": {
            "description": "permission_required: the caller lacks git.write"
          }
        },
        "x-rustybin-permission": "git.write"
      }
    },
    "/_rustybin/git/webhook": {
      "post": {
        "tags": [
          "Control Plane"
        ],
        "summary": "A signed push from a git host",
        "operationId": "gitWebhook",
        "responses": {
          "202": {
            "description": "A pull is queued"
          },
          "200": {
            "description": "Another branch, or a ping"
          },
          "401": {
            "description": "The signature does not match"
          },
          "404": {
            "description": "git.webhook_secret is not set"
          }
        },
        "x-rustybin-permission": "open"
      }
    },
    "/_rustybin/git/pull": {
      "post": {
        "tags": [
          "Control Plane"
        ],
        "summary": "Pull and apply",
        "operationId": "gitPull",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "apply": {
                    "type": "boolean",
                    "default": false
                  },
                  "dry_run": {
                    "type": "boolean",
                    "default": false
                  },
                  "prune": {
                    "type": "boolean",
                    "default": false
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "{fast_forwarded, ahead, behind, head, applied, checkpoints (the repository's, by name)}"
          },
          "401": {
            "description": "Admin rights required"
          },
          "409": {
            "description": "Not configured, not initialised, busy, or a conflict to resolve"
          },
          "502": {
            "description": "git failed (the remote, the network)"
          },
          "403": {
            "description": "permission_required: the caller lacks git.write"
          }
        },
        "x-rustybin-permission": "git.write"
      }
    },
    "/_rustybin/git/resolve": {
      "post": {
        "tags": [
          "Control Plane"
        ],
        "summary": "Resolve a diverged branch",
        "operationId": "gitResolve",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "with"
                ],
                "properties": {
                  "with": {
                    "type": "string",
                    "enum": [
                      "instance",
                      "repository"
                    ]
                  },
                  "message": {
                    "type": "string"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "{resolved, commit, push} or {resolved, applied, head}"
          },
          "401": {
            "description": "Admin rights required"
          },
          "409": {
            "description": "Not configured, not initialised, busy, or a conflict to resolve"
          },
          "502": {
            "description": "git failed (the remote, the network)"
          },
          "403": {
            "description": "permission_required: the caller lacks git.write"
          }
        },
        "x-rustybin-permission": "git.write"
      }
    },
    "/_rustybin/git/key": {
      "get": {
        "tags": [
          "Control Plane"
        ],
        "summary": "The deploy key's public half",
        "operationId": "gitKey",
        "responses": {
          "200": {
            "description": "{deploy_key: {public, path} | null}"
          },
          "401": {
            "description": "Admin rights required"
          },
          "403": {
            "description": "permission_required: the caller lacks git.read"
          }
        },
        "x-rustybin-permission": "git.read"
      },
      "post": {
        "tags": [
          "Control Plane"
        ],
        "summary": "Generate the deploy key",
        "operationId": "gitGenerateKey",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "replace": {
                    "type": "boolean",
                    "default": false
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "{public, path, generated}"
          },
          "401": {
            "description": "Admin rights required"
          },
          "409": {
            "description": "Not configured, not initialised, busy, or a conflict to resolve"
          },
          "502": {
            "description": "git failed (the remote, the network)"
          },
          "403": {
            "description": "permission_required: the caller lacks git.write"
          }
        },
        "x-rustybin-permission": "git.write"
      }
    },
    "/_rustybin/git/history": {
      "get": {
        "tags": [
          "Control Plane"
        ],
        "summary": "Commit history",
        "operationId": "gitHistory",
        "responses": {
          "200": {
            "description": "{commits: [{sha, short, author, at, subject, stat}]}"
          },
          "401": {
            "description": "Admin rights required"
          },
          "409": {
            "description": "Not configured, not initialised, busy, or a conflict to resolve"
          },
          "502": {
            "description": "git failed (the remote, the network)"
          },
          "403": {
            "description": "permission_required: the caller lacks git.read"
          }
        },
        "x-rustybin-permission": "git.read"
      }
    },
    "/_rustybin/mcp-servers": {
      "get": {
        "tags": [
          "Control Plane"
        ],
        "summary": "MCP servers of this instance",
        "operationId": "listMcpServers",
        "responses": {
          "200": {
            "description": "{servers, relay, checks}"
          },
          "403": {
            "description": "permission_required: the caller lacks mcp.inspect"
          }
        },
        "x-rustybin-permission": "mcp.inspect"
      }
    },
    "/_rustybin/mcp-relay": {
      "post": {
        "tags": [
          "Control Plane"
        ],
        "summary": "Relay one JSON-RPC message to an MCP server",
        "operationId": "mcpRelay",
        "description": "The answer streams as SSE: relay ({session, status, headers}), message per JSON-RPC message, body for a non-JSON-RPC answer, error, done. Relay sessions keep the upstream session id or the open legacy stream (at most 64, idle 10 minutes).",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "target": {
                    "type": "string",
                    "description": "A path on this instance (/mcp, /mcp/protected, /_rustybin/mcp, /mock/<name>/_rustybin/mcp) or an http(s) URL"
                  },
                  "headers": {
                    "type": "object",
                    "additionalProperties": {
                      "type": "string"
                    },
                    "description": "Headers sent upstream (MCP routing headers, credentials)"
                  },
                  "connection": {
                    "type": "string",
                    "description": "A saved connection whose credentials fill in"
                  },
                  "transport": {
                    "type": "string",
                    "enum": [
                      "streamable",
                      "legacy"
                    ]
                  },
                  "message": {
                    "type": "object",
                    "description": "One JSON-RPC message"
                  },
                  "session": {
                    "type": "string",
                    "description": "The relay session of an earlier answer"
                  },
                  "op": {
                    "type": "string",
                    "enum": [
                      "delete"
                    ]
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "text/event-stream"
          },
          "400": {
            "description": "Invalid target or message"
          },
          "403": {
            "description": "The egress policy refused the host"
          },
          "404": {
            "description": "Unknown relay session"
          },
          "502": {
            "description": "The server could not be reached"
          }
        },
        "x-rustybin-permission": "mcp.inspect"
      }
    },
    "/_rustybin/mcp-relay/fetch": {
      "post": {
        "tags": [
          "Control Plane"
        ],
        "summary": "Fetch an OAuth discovery or token document",
        "operationId": "mcpRelayFetch",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "url"
                ],
                "properties": {
                  "url": {
                    "type": "string"
                  },
                  "method": {
                    "type": "string",
                    "enum": [
                      "GET",
                      "POST"
                    ]
                  },
                  "headers": {
                    "type": "object"
                  },
                  "body": {
                    "type": "string"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "{status, headers, body, json}"
          },
          "403": {
            "description": "The egress policy refused the host"
          }
        },
        "x-rustybin-permission": "mcp.inspect"
      }
    },
    "/_rustybin/mcp-relay/{session}": {
      "delete": {
        "tags": [
          "Control Plane"
        ],
        "summary": "End a relay session",
        "operationId": "endMcpRelaySession",
        "parameters": [
          {
            "name": "session",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Ended"
          },
          "404": {
            "description": "Unknown session"
          },
          "403": {
            "description": "permission_required: the caller lacks mcp.inspect"
          }
        },
        "x-rustybin-permission": "mcp.inspect"
      }
    },
    "/_rustybin/mcp-checks": {
      "get": {
        "tags": [
          "Control Plane"
        ],
        "summary": "Saved MCP check runs",
        "operationId": "listMcpCheckRuns",
        "responses": {
          "200": {
            "description": "{runs, capacity}"
          },
          "403": {
            "description": "permission_required: the caller lacks mcp.inspect"
          }
        },
        "x-rustybin-permission": "mcp.inspect"
      },
      "post": {
        "tags": [
          "Control Plane"
        ],
        "summary": "Run the MCP check suite",
        "operationId": "runMcpChecks",
        "description": "Connect, version, auth refusal, tools/list schemas, every tool called with generated arguments, unknown tool and method, bad arguments, resources, prompts, ping, routing headers (2026-07-28), the session stream and lifecycle (session transports). A report like a harness report; format junit (or Accept: application/xml) for JUnit. Saved unless save is false.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "target": {
                    "type": "string",
                    "description": "A path on this instance (/mcp, /mcp/protected, /_rustybin/mcp, /mock/<name>/_rustybin/mcp) or an http(s) URL"
                  },
                  "headers": {
                    "type": "object",
                    "additionalProperties": {
                      "type": "string"
                    },
                    "description": "Headers sent upstream (MCP routing headers, credentials)"
                  },
                  "connection": {
                    "type": "string",
                    "description": "A saved connection whose credentials fill in"
                  },
                  "transport": {
                    "type": "string",
                    "enum": [
                      "modern",
                      "session",
                      "legacy"
                    ]
                  },
                  "version": {
                    "type": "string",
                    "enum": [
                      "2026-07-28",
                      "2025-11-25",
                      "2025-06-18",
                      "2025-03-26"
                    ]
                  },
                  "checks": {
                    "type": "array",
                    "items": {
                      "type": "string",
                      "enum": [
                        "connect",
                        "version",
                        "auth_refusal",
                        "tools_list",
                        "tools_call",
                        "unknown_tool",
                        "bad_arguments",
                        "unknown_method",
                        "resources",
                        "prompts",
                        "ping",
                        "routing_headers",
                        "server_stream",
                        "session"
                      ]
                    }
                  },
                  "include_destructive": {
                    "type": "boolean"
                  },
                  "max_tools": {
                    "type": "integer",
                    "minimum": 1,
                    "maximum": 50
                  },
                  "ai_arguments": {
                    "type": "boolean",
                    "description": "Tool arguments from the AI assist provider (else the schema generator)"
                  },
                  "save": {
                    "type": "boolean"
                  },
                  "format": {
                    "type": "string",
                    "enum": [
                      "json",
                      "junit"
                    ]
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The report (JSON or JUnit XML)"
          },
          "400": {
            "description": "Invalid target, transport or check ids"
          },
          "403": {
            "description": "permission_required: the caller lacks mcp.inspect"
          }
        },
        "x-rustybin-permission": "mcp.inspect"
      }
    },
    "/_rustybin/mcp-checks/{id}": {
      "get": {
        "tags": [
          "Control Plane"
        ],
        "summary": "A saved MCP check run",
        "operationId": "getMcpCheckRun",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "format",
            "in": "query",
            "schema": {
              "type": "string",
              "enum": [
                "json",
                "junit"
              ]
            }
          }
        ],
        "responses": {
          "200": {
            "description": "The report"
          },
          "404": {
            "description": "Unknown run"
          },
          "403": {
            "description": "permission_required: the caller lacks mcp.inspect"
          }
        },
        "x-rustybin-permission": "mcp.inspect"
      },
      "delete": {
        "tags": [
          "Control Plane"
        ],
        "summary": "Delete a saved run (admin)",
        "operationId": "deleteMcpCheckRun",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Deleted"
          },
          "404": {
            "description": "Unknown run"
          },
          "403": {
            "description": "permission_required: the caller lacks mcp.connections"
          }
        },
        "x-rustybin-permission": "mcp.connections"
      }
    },
    "/_rustybin/mcp-connections": {
      "get": {
        "tags": [
          "Control Plane"
        ],
        "summary": "Saved MCP connections",
        "operationId": "listMcpConnections",
        "responses": {
          "200": {
            "description": "{connections, capacity, persisted}"
          },
          "403": {
            "description": "permission_required: the caller lacks mcp.inspect"
          }
        },
        "x-rustybin-permission": "mcp.inspect"
      }
    },
    "/_rustybin/mcp-connections/{id}": {
      "get": {
        "tags": [
          "Control Plane"
        ],
        "summary": "A saved MCP connection",
        "operationId": "getMcpConnection",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "The connection; secrets as {set, hint}"
          },
          "404": {
            "description": "Unknown connection"
          },
          "403": {
            "description": "permission_required: the caller lacks mcp.inspect"
          }
        },
        "x-rustybin-permission": "mcp.inspect"
      },
      "put": {
        "tags": [
          "Control Plane"
        ],
        "summary": "Save an MCP connection (admin)",
        "operationId": "putMcpConnection",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "name",
                  "target"
                ],
                "properties": {
                  "name": {
                    "type": "string"
                  },
                  "target": {
                    "type": "string"
                  },
                  "transport": {
                    "type": "string",
                    "enum": [
                      "modern",
                      "session",
                      "legacy"
                    ]
                  },
                  "version": {
                    "type": "string"
                  },
                  "mode": {
                    "type": "string",
                    "enum": [
                      "browser",
                      "relay"
                    ]
                  },
                  "auth": {
                    "type": "object",
                    "properties": {
                      "kind": {
                        "type": "string",
                        "enum": [
                          "none",
                          "bearer",
                          "api_key",
                          "basic",
                          "headers",
                          "oauth"
                        ]
                      },
                      "name": {
                        "type": "string"
                      },
                      "location": {
                        "type": "string",
                        "enum": [
                          "header",
                          "query"
                        ]
                      },
                      "username": {
                        "type": "string"
                      },
                      "headers": {
                        "type": "array",
                        "items": {
                          "type": "string"
                        }
                      },
                      "oauth": {
                        "type": "object"
                      }
                    }
                  },
                  "secrets": {
                    "type": "object",
                    "description": "token, api_key, password, refresh_token, client_secret or header:<name>; null clears, absent keeps"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The saved connection"
          },
          "400": {
            "description": "Invalid connection"
          },
          "403": {
            "description": "permission_required: the caller lacks mcp.connections"
          }
        },
        "x-rustybin-permission": "mcp.connections"
      },
      "delete": {
        "tags": [
          "Control Plane"
        ],
        "summary": "Delete a saved MCP connection (admin)",
        "operationId": "deleteMcpConnection",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Deleted"
          },
          "404": {
            "description": "Unknown connection"
          },
          "403": {
            "description": "permission_required: the caller lacks mcp.connections"
          }
        },
        "x-rustybin-permission": "mcp.connections"
      }
    },
    "/mcp-registry": {
      "get": {
        "tags": [
          "MCP"
        ],
        "summary": "The mock MCP registry",
        "operationId": "registryIndex",
        "responses": {
          "200": {
            "description": "{name, api, aliases, servers, schema, scenario}"
          }
        }
      }
    },
    "/mcp-registry/v0.1/servers": {
      "get": {
        "tags": [
          "MCP"
        ],
        "summary": "List MCP servers",
        "operationId": "registryListServers",
        "description": "One record per server version, ordered by name then version (as text). version=latest for the latest of each. Follow metadata.nextCursor with the same filters.",
        "parameters": [
          {
            "name": "cursor",
            "in": "query",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "limit",
            "in": "query",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 100,
              "default": 30
            }
          },
          {
            "name": "updated_since",
            "in": "query",
            "schema": {
              "type": "string",
              "format": "date-time"
            }
          },
          {
            "name": "search",
            "in": "query",
            "description": "Substring of the name, at least 3 characters",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "version",
            "in": "query",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "include_deleted",
            "in": "query",
            "schema": {
              "type": "boolean"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "A ServerListResponse",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/RegistryServerList"
                }
              }
            }
          },
          "422": {
            "description": "A problem (application/problem+json)",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/RegistryProblem"
                }
              }
            }
          },
          "503": {
            "description": "A problem (application/problem+json)",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/RegistryProblem"
                }
              }
            }
          }
        }
      }
    },
    "/mcp-registry/v0.1/servers/{serverName}/versions": {
      "get": {
        "tags": [
          "MCP"
        ],
        "summary": "Every version of a server",
        "operationId": "registryServerVersions",
        "parameters": [
          {
            "name": "serverName",
            "in": "path",
            "required": true,
            "description": "The server name, URL-encoded (io.rustybin%2Fmcp)",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "include_deleted",
            "in": "query",
            "schema": {
              "type": "boolean"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "A ServerListResponse",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/RegistryServerList"
                }
              }
            }
          },
          "404": {
            "description": "A problem (application/problem+json)",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/RegistryProblem"
                }
              }
            }
          }
        }
      }
    },
    "/mcp-registry/v0.1/servers/{serverName}/versions/{version}": {
      "get": {
        "tags": [
          "MCP"
        ],
        "summary": "One version of a server",
        "operationId": "registryServerVersion",
        "parameters": [
          {
            "name": "serverName",
            "in": "path",
            "required": true,
            "description": "The server name, URL-encoded (io.rustybin%2Fmcp)",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "version",
            "in": "path",
            "required": true,
            "description": "An exact version, or latest",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "include_deleted",
            "in": "query",
            "schema": {
              "type": "boolean"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "A ServerResponse",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/RegistryServerResponse"
                }
              }
            }
          },
          "404": {
            "description": "A problem (application/problem+json)",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/RegistryProblem"
                }
              }
            }
          }
        }
      }
    },
    "/mcp-registry/v0.1/servers/{serverName}/versions/{version}/status": {
      "patch": {
        "tags": [
          "MCP"
        ],
        "summary": "Change the status of a published version",
        "operationId": "registryVersionStatus",
        "parameters": [
          {
            "name": "Authorization",
            "in": "header",
            "required": true,
            "description": "Bearer <registry token from auth/*>",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "serverName",
            "in": "path",
            "required": true,
            "description": "The server name, URL-encoded (io.rustybin%2Fmcp)",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "version",
            "in": "path",
            "required": true,
            "description": "An exact version, or latest",
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "status"
                ],
                "properties": {
                  "status": {
                    "type": "string",
                    "enum": [
                      "active",
                      "deprecated",
                      "deleted"
                    ]
                  },
                  "statusMessage": {
                    "type": "string",
                    "maxLength": 500
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "A ServerResponse",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/RegistryServerResponse"
                }
              }
            }
          },
          "401": {
            "description": "A problem (application/problem+json)",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/RegistryProblem"
                }
              }
            }
          },
          "403": {
            "description": "A problem (application/problem+json)",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/RegistryProblem"
                }
              }
            }
          },
          "404": {
            "description": "A problem (application/problem+json)",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/RegistryProblem"
                }
              }
            }
          }
        }
      }
    },
    "/mcp-registry/v0.1/servers/{serverName}/status": {
      "patch": {
        "tags": [
          "MCP"
        ],
        "summary": "Change the status of every published version of a server",
        "operationId": "registryServerStatus",
        "parameters": [
          {
            "name": "Authorization",
            "in": "header",
            "required": true,
            "description": "Bearer <registry token from auth/*>",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "serverName",
            "in": "path",
            "required": true,
            "description": "The server name, URL-encoded (io.rustybin%2Fmcp)",
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "status"
                ],
                "properties": {
                  "status": {
                    "type": "string",
                    "enum": [
                      "active",
                      "deprecated",
                      "deleted"
                    ]
                  },
                  "statusMessage": {
                    "type": "string",
                    "maxLength": 500
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "{updatedCount, servers}"
          },
          "401": {
            "description": "A problem (application/problem+json)",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/RegistryProblem"
                }
              }
            }
          },
          "403": {
            "description": "A problem (application/problem+json)",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/RegistryProblem"
                }
              }
            }
          },
          "404": {
            "description": "A problem (application/problem+json)",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/RegistryProblem"
                }
              }
            }
          }
        }
      }
    },
    "/mcp-registry/v0.1/publish": {
      "post": {
        "tags": [
          "MCP"
        ],
        "summary": "Publish a server.json",
        "operationId": "registryPublish",
        "description": "Validated against the vendored server.json schema and the semantic checks. The io.rustybin namespace is reserved; a duplicate version is refused; at most 256 file and published entries. In public mode the admin token is needed as X-Rustybin-Admin-Token.",
        "parameters": [
          {
            "name": "Authorization",
            "in": "header",
            "required": true,
            "description": "Bearer <registry token from auth/*>",
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/RegistryServerJson"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "A ServerResponse",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/RegistryServerResponse"
                }
              }
            }
          },
          "400": {
            "description": "A problem (application/problem+json)",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/RegistryProblem"
                }
              }
            }
          },
          "401": {
            "description": "A problem (application/problem+json)",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/RegistryProblem"
                }
              }
            }
          },
          "403": {
            "description": "A problem (application/problem+json)",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/RegistryProblem"
                }
              }
            }
          },
          "409": {
            "description": "A problem (application/problem+json)",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/RegistryProblem"
                }
              }
            }
          },
          "422": {
            "description": "A problem (application/problem+json)",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/RegistryProblem"
                }
              }
            }
          }
        }
      }
    },
    "/mcp-registry/v0.1/validate": {
      "post": {
        "tags": [
          "MCP"
        ],
        "summary": "Validate a server.json",
        "operationId": "registryValidate",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/RegistryServerJson"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "{valid, issues: [{type, path, message, severity, reference}]}",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/RegistryValidation"
                }
              }
            }
          },
          "400": {
            "description": "A problem (application/problem+json)",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/RegistryProblem"
                }
              }
            }
          }
        }
      }
    },
    "/mcp-registry/v0.1/auth/{method}": {
      "post": {
        "tags": [
          "MCP"
        ],
        "summary": "Exchange a credential for a registry token (stub)",
        "operationId": "registryAuth",
        "description": "github-at {github_token}, github-oidc and oidc {oidc_token}, dns and http {domain, timestamp, signed_timestamp}, none {}. Every credential is accepted (nothing is verified), except in the auth_fail scenario, where every exchange answers 401. Tokens last 5 minutes.",
        "parameters": [
          {
            "name": "method",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "enum": [
                "github-at",
                "github-oidc",
                "oidc",
                "dns",
                "http",
                "none"
              ]
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "type": "object"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "{registry_token, expires_at}"
          },
          "401": {
            "description": "A problem (application/problem+json)",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/RegistryProblem"
                }
              }
            }
          },
          "404": {
            "description": "A problem (application/problem+json)",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/RegistryProblem"
                }
              }
            }
          },
          "422": {
            "description": "A problem (application/problem+json)",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/RegistryProblem"
                }
              }
            }
          }
        }
      }
    },
    "/mcp-registry/v0.1/health": {
      "get": {
        "tags": [
          "MCP"
        ],
        "summary": "Registry health",
        "operationId": "registryHealth",
        "responses": {
          "200": {
            "description": "{status}"
          }
        }
      }
    },
    "/mcp-registry/v0.1/ping": {
      "get": {
        "tags": [
          "MCP"
        ],
        "summary": "Registry ping",
        "operationId": "registryPing",
        "responses": {
          "200": {
            "description": "{pong}"
          }
        }
      }
    },
    "/mcp-registry/v0.1/version": {
      "get": {
        "tags": [
          "MCP"
        ],
        "summary": "Registry version",
        "operationId": "registryVersion",
        "responses": {
          "200": {
            "description": "{version, git_commit, build_time}"
          }
        }
      }
    },
    "/mcp-registry/v0/{path}": {
      "get": {
        "tags": [
          "MCP"
        ],
        "summary": "The /v0.1 API under /v0",
        "operationId": "registryV0Get",
        "parameters": [
          {
            "name": "path",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "As /v0.1"
          }
        }
      },
      "post": {
        "tags": [
          "MCP"
        ],
        "summary": "The /v0.1 API under /v0",
        "operationId": "registryV0Post",
        "parameters": [
          {
            "name": "path",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "As /v0.1"
          }
        }
      },
      "put": {
        "tags": [
          "MCP"
        ],
        "summary": "The /v0.1 API under /v0",
        "operationId": "registryV0Put",
        "parameters": [
          {
            "name": "path",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "As /v0.1"
          }
        }
      },
      "patch": {
        "tags": [
          "MCP"
        ],
        "summary": "The /v0.1 API under /v0",
        "operationId": "registryV0Patch",
        "parameters": [
          {
            "name": "path",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "As /v0.1"
          }
        }
      },
      "delete": {
        "tags": [
          "MCP"
        ],
        "summary": "The /v0.1 API under /v0",
        "operationId": "registryV0Delete",
        "parameters": [
          {
            "name": "path",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "As /v0.1"
          }
        }
      }
    },
    "/_rustybin/registry": {
      "get": {
        "tags": [
          "Control Plane"
        ],
        "summary": "The mock registry's state",
        "operationId": "registryState",
        "responses": {
          "200": {
            "description": "{path, api, base_url, scenario, scenarios, entries, counts, capacity, saved, sync_config}"
          },
          "403": {
            "description": "permission_required: the caller lacks instance.read"
          }
        },
        "x-rustybin-permission": "instance.read"
      }
    },
    "/_rustybin/registry/servers/{serverName}": {
      "delete": {
        "tags": [
          "Control Plane"
        ],
        "summary": "Remove a published entry (admin)",
        "operationId": "registryDeleteServer",
        "parameters": [
          {
            "name": "serverName",
            "in": "path",
            "required": true,
            "description": "The server name, URL-encoded (io.rustybin%2Fmcp)",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "version",
            "in": "query",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "{deleted, versions}"
          },
          "404": {
            "description": "No published entry"
          },
          "403": {
            "description": "permission_required: the caller lacks registry.write"
          }
        },
        "x-rustybin-permission": "registry.write"
      }
    },
    "/_rustybin/registry/validate": {
      "post": {
        "tags": [
          "Control Plane"
        ],
        "summary": "Validate a server.json",
        "operationId": "registryValidateControl",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/RegistryServerJson"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "{valid, issues: [{type, path, message, severity, reference}]}",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/RegistryValidation"
                }
              }
            }
          },
          "400": {
            "description": "Not JSON"
          },
          "403": {
            "description": "permission_required: the caller lacks instance.read"
          }
        },
        "x-rustybin-permission": "instance.read"
      }
    },
    "/_rustybin/registry/browse": {
      "get": {
        "tags": [
          "Control Plane"
        ],
        "summary": "Browse an MCP registry",
        "operationId": "registryBrowse",
        "parameters": [
          {
            "name": "url",
            "in": "query",
            "description": "A registry base URL, or /mcp-registry for this instance",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "search",
            "in": "query",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "cursor",
            "in": "query",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "limit",
            "in": "query",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 100
            }
          },
          {
            "name": "version",
            "in": "query",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "{registry, request, status, cached, fetched_at, count, next_cursor, servers: [{name, title, description, version, status, remotes: [{type, url, headers, auth}], packages, valid, issues, server}]}"
          },
          "400": {
            "description": "Invalid url"
          },
          "403": {
            "description": "The egress policy refused the host"
          },
          "502": {
            "description": "The registry failed or did not answer"
          }
        },
        "x-rustybin-permission": "mcp.inspect"
      }
    },
    "/_rustybin/portal": {
      "get": {
        "tags": [
          "Control Plane"
        ],
        "summary": "Dev portal items and settings",
        "operationId": "getPortal",
        "responses": {
          "200": {
            "description": "Settings, items, counts",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "403": {
            "description": "permission_required: the caller lacks instance.read"
          }
        },
        "x-rustybin-permission": "instance.read"
      }
    },
    "/_rustybin/portal/items/{id}": {
      "put": {
        "tags": [
          "Control Plane"
        ],
        "summary": "Publish an item to the dev portal",
        "operationId": "publishPortalItem",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "mock:<name>, mcp:<server>, llm, a2a:<agent>, tools or registry"
          }
        ],
        "requestBody": {
          "required": false,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "title": {
                    "type": "string",
                    "maxLength": 120
                  },
                  "summary": {
                    "type": "string",
                    "maxLength": 2000,
                    "description": "Markdown"
                  },
                  "tags": {
                    "type": "array",
                    "items": {
                      "type": "string",
                      "maxLength": 40
                    },
                    "maxItems": 10
                  },
                  "contact": {
                    "type": "string",
                    "maxLength": 200
                  },
                  "order": {
                    "type": "integer",
                    "minimum": -1000,
                    "maximum": 1000
                  },
                  "credentials": {
                    "type": "boolean",
                    "description": "Show a mock's demo credentials (default true)"
                  },
                  "access": {
                    "type": "string",
                    "enum": [
                      "open",
                      "closed"
                    ],
                    "description": "open (default): anyone uses it; closed: everyone reads it, only portal readers (portal.read) use it"
                  },
                  "secure": {
                    "type": "boolean",
                    "description": "With access closed on a mock that cannot be closed as it is: turn its security on with random credentials in place of the defaults (api_key mode unless the spec's or basic mode closes it) and deploy it first (needs mocks.write)"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Updated"
          },
          "201": {
            "description": "Published"
          },
          "400": {
            "description": "Invalid id or metadata"
          },
          "403": {
            "description": "Not allowed"
          },
          "404": {
            "description": "Unknown mock"
          },
          "409": {
            "description": "Defined in the config file, the portal is full, a mock that cannot be closed (security_off, default_credentials, obtainable_credentials, open_operations), or a draft not deployed (secure)"
          }
        },
        "x-rustybin-permission": "portal.publish"
      },
      "delete": {
        "tags": [
          "Control Plane"
        ],
        "summary": "Unpublish an item",
        "operationId": "unpublishPortalItem",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "mock:<name>, mcp:<server>, llm, a2a:<agent>, tools or registry"
          }
        ],
        "responses": {
          "200": {
            "description": "Unpublished"
          },
          "404": {
            "description": "Not published"
          },
          "409": {
            "description": "Defined in the config file"
          },
          "403": {
            "description": "permission_required: the caller lacks portal.publish"
          }
        },
        "x-rustybin-permission": "portal.publish"
      }
    },
    "/_rustybin/portal/insights": {
      "get": {
        "tags": [
          "Control Plane"
        ],
        "summary": "Dev portal insights",
        "operationId": "getPortalInsights",
        "responses": {
          "200": {
            "description": "Counters per item",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "403": {
            "description": "permission_required: the caller lacks instance.read"
          }
        },
        "x-rustybin-permission": "instance.read"
      }
    },
    "/portal": {
      "get": {
        "tags": [
          "Docs"
        ],
        "summary": "Dev portal",
        "operationId": "getPortalRedirect",
        "responses": {
          "307": {
            "description": "Redirect to /portal/"
          },
          "404": {
            "description": "The portal is off"
          }
        }
      }
    },
    "/portal/": {
      "get": {
        "tags": [
          "Docs"
        ],
        "summary": "Dev portal entry page",
        "operationId": "getPortalIndex",
        "responses": {
          "200": {
            "description": "HTML"
          },
          "404": {
            "description": "The portal is off"
          }
        }
      }
    },
    "/portal/{path}": {
      "get": {
        "tags": [
          "Docs"
        ],
        "summary": "Dev portal asset (SPA fallback to index.html)",
        "operationId": "getPortalAsset",
        "parameters": [
          {
            "name": "path",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Asset"
          },
          "304": {
            "description": "Not modified"
          },
          "404": {
            "description": "Unknown asset, or the portal is off"
          }
        }
      }
    },
    "/portal/api/catalog": {
      "get": {
        "tags": [
          "Docs"
        ],
        "summary": "Dev portal catalogue",
        "operationId": "getPortalCatalog",
        "responses": {
          "200": {
            "description": "Published items",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "portal": {
                      "type": "object"
                    },
                    "kinds": {
                      "type": "array",
                      "items": {
                        "type": "object"
                      }
                    },
                    "items": {
                      "type": "array",
                      "items": {
                        "type": "object"
                      }
                    },
                    "whats_new": {
                      "type": "array",
                      "items": {
                        "type": "string"
                      }
                    }
                  }
                }
              }
            }
          },
          "304": {
            "description": "Not modified"
          },
          "401": {
            "description": "portal.auth asks for a credential"
          },
          "404": {
            "description": "The portal is off"
          }
        }
      }
    },
    "/portal/api/events": {
      "post": {
        "tags": [
          "Docs"
        ],
        "summary": "Count a portal view or Try it call",
        "operationId": "postPortalEvent",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "item",
                  "event"
                ],
                "properties": {
                  "item": {
                    "type": "string"
                  },
                  "event": {
                    "type": "string",
                    "enum": [
                      "view",
                      "try"
                    ]
                  }
                }
              }
            }
          }
        },
        "responses": {
          "204": {
            "description": "Counted"
          },
          "400": {
            "description": "Invalid event"
          },
          "401": {
            "description": "A Try it of a closed item, not signed in"
          },
          "404": {
            "description": "No such published item"
          }
        }
      }
    },
    "/portal/api/items/{id}/collections/{format}": {
      "get": {
        "tags": [
          "Docs"
        ],
        "summary": "A published mock as a collection",
        "operationId": "getPortalCollection",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "mock:<name>, mcp:<server>, llm, a2a:<agent>, tools or registry"
          },
          {
            "name": "format",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "enum": [
                "postman",
                "hurl",
                "curl",
                "http",
                "k6",
                "bruno",
                "insomnia"
              ]
            }
          }
        ],
        "responses": {
          "200": {
            "description": "The collection (attachment)"
          },
          "401": {
            "description": "A closed item, not signed in (collections carry the credentials)"
          },
          "403": {
            "description": "Signed in without portal.read"
          },
          "404": {
            "description": "Not published, or an unknown format"
          }
        }
      }
    },
    "/portal/reference/{id}": {
      "get": {
        "tags": [
          "Docs"
        ],
        "summary": "A published mock's API reference",
        "operationId": "getPortalReference",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "mock:<name>, mcp:<server>, llm, a2a:<agent>, tools or registry"
          }
        ],
        "responses": {
          "200": {
            "description": "HTML"
          },
          "401": {
            "description": "portal.auth=password, not signed in"
          },
          "404": {
            "description": "Not published"
          }
        }
      }
    },
    "/portal/api/login": {
      "post": {
        "tags": [
          "Docs"
        ],
        "summary": "Dev portal sign-in",
        "operationId": "portalLogin",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "username",
                  "password"
                ],
                "properties": {
                  "username": {
                    "type": "string"
                  },
                  "password": {
                    "type": "string",
                    "format": "password"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Signed in: Set-Cookie rustybin_portal",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "signed_in": {
                      "type": "boolean"
                    },
                    "user": {
                      "type": "string"
                    },
                    "display_name": {
                      "type": "string"
                    },
                    "reader": {
                      "type": "boolean"
                    },
                    "expires_in": {
                      "type": "integer"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Invalid body"
          },
          "401": {
            "description": "Invalid user name or password"
          },
          "404": {
            "description": "The portal or its sign-in is off"
          },
          "429": {
            "description": "Too many failed attempts (shared with the console sign-in)"
          }
        }
      }
    },
    "/portal/api/logout": {
      "post": {
        "tags": [
          "Docs"
        ],
        "summary": "Dev portal sign-out",
        "operationId": "portalLogout",
        "responses": {
          "200": {
            "description": "Signed out, the cookie cleared"
          },
          "404": {
            "description": "The portal is off"
          }
        }
      }
    },
    "/portal/api/session": {
      "get": {
        "tags": [
          "Docs"
        ],
        "summary": "Dev portal session",
        "operationId": "portalSession",
        "responses": {
          "200": {
            "description": "Who is signed in",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "signed_in": {
                      "type": "boolean"
                    },
                    "via": {
                      "type": "string",
                      "enum": [
                        "cookie",
                        "bearer"
                      ]
                    },
                    "user": {
                      "type": "string"
                    },
                    "display_name": {
                      "type": "string"
                    },
                    "reader": {
                      "type": "boolean"
                    },
                    "signin": {
                      "type": "boolean"
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "The portal is off"
          }
        }
      }
    },
    "/.well-known/oauth-protected-resource/_rustybin/mcp": {
      "get": {
        "tags": [
          "Control Plane"
        ],
        "summary": "Protected resource metadata of /_rustybin/mcp (RFC 9728)",
        "operationId": "getManageMcpResourceMetadata",
        "responses": {
          "200": {
            "description": "Metadata"
          },
          "404": {
            "description": "OAuth sign-in is off on this instance"
          }
        }
      }
    },
    "/.well-known/oauth-authorization-server/_rustybin/oauth": {
      "get": {
        "tags": [
          "Control Plane"
        ],
        "summary": "Authorization server metadata (RFC 8414)",
        "operationId": "getControlOAuthMetadata",
        "responses": {
          "200": {
            "description": "Metadata"
          },
          "404": {
            "description": "OAuth sign-in is off on this instance"
          }
        }
      }
    },
    "/.well-known/openid-configuration/_rustybin/oauth": {
      "get": {
        "tags": [
          "Control Plane"
        ],
        "summary": "Authorization server metadata (OpenID Connect discovery path)",
        "operationId": "getControlOAuthOidcMetadata",
        "responses": {
          "200": {
            "description": "Metadata"
          },
          "404": {
            "description": "OAuth sign-in is off on this instance"
          }
        }
      }
    },
    "/_rustybin/oauth/register": {
      "post": {
        "tags": [
          "Control Plane"
        ],
        "summary": "Register a public client (RFC 7591)",
        "operationId": "registerControlOAuthClient",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "redirect_uris"
                ],
                "properties": {
                  "redirect_uris": {
                    "type": "array",
                    "items": {
                      "type": "string"
                    },
                    "maxItems": 3
                  },
                  "client_name": {
                    "type": "string"
                  },
                  "grant_types": {
                    "type": "array",
                    "items": {
                      "type": "string"
                    }
                  },
                  "token_endpoint_auth_method": {
                    "type": "string",
                    "enum": [
                      "none"
                    ]
                  }
                }
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Registered"
          },
          "400": {
            "description": "Invalid metadata"
          },
          "404": {
            "description": "OAuth sign-in is off"
          }
        },
        "x-rustybin-permission": "open"
      }
    },
    "/_rustybin/oauth/authorize": {
      "get": {
        "tags": [
          "Control Plane"
        ],
        "summary": "Authorization endpoint: redirects to the console's consent page",
        "operationId": "authorizeControlOAuth",
        "parameters": [
          {
            "name": "response_type",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "client_id",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "redirect_uri",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "code_challenge",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "code_challenge_method",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "scope",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "state",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "resource",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "302": {
            "description": "To the consent page, or back to the client with an error"
          },
          "400": {
            "description": "Unknown client or redirect URI (HTML page)"
          },
          "404": {
            "description": "OAuth sign-in is off"
          }
        },
        "x-rustybin-permission": "open"
      }
    },
    "/_rustybin/oauth/requests/{id}": {
      "get": {
        "tags": [
          "Control Plane"
        ],
        "summary": "A pending sign-in request (for the consent page)",
        "operationId": "getControlOAuthRequest",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "The request: the client, the scopes asked for and grantable, the approver, and what the agent will hold (grants per scope, permissions; a user's agent holds the user's permissions within the scope)"
          },
          "401": {
            "description": "Control-plane credentials required"
          },
          "404": {
            "description": "Unknown or expired"
          }
        },
        "x-rustybin-permission": "signed in"
      },
      "post": {
        "tags": [
          "Control Plane"
        ],
        "summary": "Approve or deny a pending sign-in request",
        "operationId": "answerControlOAuthRequest",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "decision"
                ],
                "properties": {
                  "decision": {
                    "type": "string",
                    "enum": [
                      "approve",
                      "deny"
                    ]
                  },
                  "scope": {
                    "type": "string",
                    "description": "Space separated: admin, console, inspector, harness (default: what the agent asked for, capped by the approver's grant)"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Where to send the browser (redirect_to)"
          },
          "403": {
            "description": "The approver's credential cannot grant the scopes"
          },
          "404": {
            "description": "Unknown or expired"
          }
        },
        "x-rustybin-permission": "signed in"
      }
    },
    "/_rustybin/oauth/token": {
      "post": {
        "tags": [
          "Control Plane"
        ],
        "summary": "Token endpoint (authorization_code with PKCE S256, refresh_token)",
        "operationId": "controlOAuthToken",
        "requestBody": {
          "required": true,
          "content": {
            "application/x-www-form-urlencoded": {
              "schema": {
                "type": "object",
                "required": [
                  "grant_type",
                  "client_id"
                ],
                "properties": {
                  "grant_type": {
                    "type": "string",
                    "enum": [
                      "authorization_code",
                      "refresh_token"
                    ]
                  },
                  "client_id": {
                    "type": "string"
                  },
                  "code": {
                    "type": "string"
                  },
                  "code_verifier": {
                    "type": "string"
                  },
                  "redirect_uri": {
                    "type": "string"
                  },
                  "refresh_token": {
                    "type": "string"
                  },
                  "scope": {
                    "type": "string"
                  },
                  "resource": {
                    "type": "string"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Tokens"
          },
          "400": {
            "description": "OAuth error"
          },
          "401": {
            "description": "Unknown client"
          },
          "404": {
            "description": "OAuth sign-in is off"
          }
        },
        "x-rustybin-permission": "open"
      }
    },
    "/_rustybin/login": {
      "post": {
        "tags": [
          "Control Plane"
        ],
        "summary": "Console sign-in",
        "description": "Looks the user up in the user store and checks the password: the first admin's is the sign-in settings' (RUSTYBIN_CONSOLE_USER, RUSTYBIN_CONSOLE_PASSWORD or _HASH, the stored console.password_hash; rustybin / rustybin by default). Answers a 12 hour control token whose permissions are the user's roles, resolved at every request (a disabled user is answered as a wrong password). Never behind control-plane auth. After 5 failed attempts from one client address within a minute the address waits (429, Retry-After, doubling up to 10 minutes).",
        "operationId": "consoleLogin",
        "security": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "username",
                  "password"
                ],
                "properties": {
                  "username": {
                    "type": "string"
                  },
                  "password": {
                    "type": "string"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Signed in",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "token": {
                      "type": "string",
                      "description": "A control token (HS256 JWT): send it as Authorization: Bearer"
                    },
                    "token_type": {
                      "type": "string",
                      "enum": [
                        "Bearer"
                      ]
                    },
                    "expires_in": {
                      "type": "integer"
                    },
                    "expires_at": {
                      "type": "string",
                      "format": "date-time"
                    },
                    "scopes": {
                      "type": "array",
                      "items": {
                        "type": "string"
                      }
                    },
                    "user": {
                      "type": "string"
                    },
                    "user_id": {
                      "type": "string",
                      "description": "The user's id in the user store (usr_ plus 16 hex)"
                    },
                    "default_password": {
                      "type": "boolean",
                      "description": "The instance still signs in with the default password"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Wrong user name or password (reason invalid_credentials)"
          },
          "404": {
            "description": "Not in password mode (or shared mode)"
          },
          "429": {
            "description": "Too many failed attempts from this address (Retry-After)"
          }
        },
        "x-rustybin-permission": "open"
      }
    },
    "/_rustybin/logout": {
      "post": {
        "tags": [
          "Control Plane"
        ],
        "summary": "Console sign-out",
        "description": "Revokes the presented sign-in token for the rest of its life (a bounded denylist of token ids). Other credentials answer revoked: false.",
        "operationId": "consoleLogout",
        "responses": {
          "200": {
            "description": "Done",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "revoked": {
                      "type": "boolean"
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "Not in password mode (or shared mode)"
          }
        },
        "x-rustybin-permission": "signed in"
      }
    },
    "/_rustybin/session": {
      "get": {
        "tags": [
          "Control Plane"
        ],
        "summary": "This session",
        "description": "Describes the credential the request presents: obtained (password, admin_token, control_jwt, api_key), the user (user, user_id, display_name) of a sign-in token, the roles and permissions resolved at this request, scopes, issue and expiry times, plus whether the instance still uses the default password.",
        "operationId": "getConsoleSession",
        "responses": {
          "200": {
            "description": "The session",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "control_auth": {
                      "type": "string"
                    },
                    "obtained": {
                      "type": "string",
                      "enum": [
                        "password",
                        "sso",
                        "admin_token",
                        "control_jwt",
                        "api_key"
                      ],
                      "description": "How the credential was obtained: password and sso are sign-in tokens (the user's own password, or single sign-on)"
                    },
                    "user": {
                      "type": [
                        "string",
                        "null"
                      ],
                      "description": "The sign-in name (sign-in tokens)"
                    },
                    "user_id": {
                      "type": [
                        "string",
                        "null"
                      ],
                      "description": "The user's id (sign-in tokens): usr_ plus 16 hex"
                    },
                    "display_name": {
                      "type": [
                        "string",
                        "null"
                      ]
                    },
                    "roles": {
                      "type": "array",
                      "items": {
                        "type": "string"
                      },
                      "description": "The roles the permissions come from (admin for the admin token; a control JWT's scopes as roles plus rb_roles)"
                    },
                    "permissions": {
                      "type": "array",
                      "items": {
                        "type": "string"
                      },
                      "description": "The caller's permissions, resolved at this request (dotted names, mocks.write)"
                    },
                    "scopes": {
                      "type": "array",
                      "items": {
                        "type": "string"
                      },
                      "description": "The 0.3 scopes these permissions amount to"
                    },
                    "sub": {
                      "type": "string",
                      "description": "The sub claim of a control JWT"
                    },
                    "id": {
                      "type": "string",
                      "description": "The session id of a sign-in token"
                    },
                    "issued_at": {
                      "type": "string",
                      "format": "date-time"
                    },
                    "expires_at": {
                      "type": "string",
                      "format": "date-time"
                    },
                    "default_password": {
                      "type": "boolean"
                    },
                    "sign_in_user": {
                      "type": [
                        "string",
                        "null"
                      ],
                      "description": "The first admin's sign-in name (password mode)"
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "The control plane is open"
          }
        },
        "x-rustybin-permission": "signed in"
      }
    },
    "/_rustybin/sessions": {
      "get": {
        "tags": [
          "Control Plane"
        ],
        "summary": "Sign-in sessions",
        "description": "The sign-in tokens issued since the last restart or sign-out-everywhere (at most 16 per user and 4096 in all, newest first; a sign-in past a user's 16 ends their oldest session): id, user, user_id, issue, expiry and last use times, client address. Admin.",
        "operationId": "listConsoleSessions",
        "responses": {
          "200": {
            "description": "Sessions",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "generation": {
                      "type": "integer"
                    },
                    "count": {
                      "type": "integer"
                    },
                    "current": {
                      "type": [
                        "string",
                        "null"
                      ],
                      "description": "The caller's own session id"
                    },
                    "sessions": {
                      "type": "array",
                      "items": {
                        "type": "object"
                      }
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "Not in password mode (or shared mode)"
          },
          "403": {
            "description": "permission_required: the caller lacks users.read"
          }
        },
        "x-rustybin-permission": "users.read"
      },
      "delete": {
        "tags": [
          "Control Plane"
        ],
        "summary": "Sign out everywhere",
        "description": "Rotates the token generation: every sign-in token issued before now is refused, the caller's included, and every OAuth and agent token. Needs every permission (the admin role or the admin token).",
        "operationId": "endAllConsoleSessions",
        "responses": {
          "200": {
            "description": "Done",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "ended": {
                      "type": "integer"
                    },
                    "generation": {
                      "type": "integer"
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "Not in password mode (or shared mode)"
          },
          "403": {
            "description": "permission_required: the caller lacks users.manage"
          }
        },
        "x-rustybin-permission": "users.manage"
      }
    },
    "/_rustybin/sessions/{id}": {
      "delete": {
        "tags": [
          "Control Plane"
        ],
        "summary": "End a sign-in session",
        "description": "Needs users.manage plus every permission the session's user holds (in the instance and in their projects), as for any change to that user.",
        "operationId": "endConsoleSession",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Done (ended: false when the session is not listed)",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "ended": {
                      "type": "boolean"
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "Not in password mode (or shared mode)"
          },
          "403": {
            "description": "permission_required: the caller lacks users.manage"
          }
        },
        "x-rustybin-permission": "users.manage"
      }
    },
    "/_rustybin/password": {
      "put": {
        "tags": [
          "Control Plane"
        ],
        "summary": "Change the console user name and password",
        "description": "Needs admin and the current password. The new password (8 to 256 characters, not the default) is stored as an argon2id hash in the secret console.password_hash; a new username goes to console.user. Every other sign-in session ends and the caller gets a fresh token when it signed in with one.",
        "operationId": "changeConsolePassword",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "current_password",
                  "new_password"
                ],
                "properties": {
                  "current_password": {
                    "type": "string"
                  },
                  "new_password": {
                    "type": "string",
                    "minLength": 8,
                    "maxLength": 256
                  },
                  "username": {
                    "type": "string",
                    "description": "A new user name (letters, digits and . _ @ -)"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Changed",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "changed": {
                      "type": "boolean"
                    },
                    "user": {
                      "type": "string"
                    },
                    "signed_out": {
                      "type": "integer"
                    },
                    "token": {
                      "type": "string"
                    },
                    "expires_at": {
                      "type": "string",
                      "format": "date-time"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "The new password or user name breaks a rule"
          },
          "403": {
            "description": "The current password is wrong"
          },
          "404": {
            "description": "Not in password mode (or shared mode)"
          },
          "409": {
            "description": "RUSTYBIN_SETTINGS_LOCK holds the sign-in settings"
          }
        },
        "x-rustybin-permission": "signed in"
      }
    },
    "/_rustybin/me/password": {
      "put": {
        "tags": [
          "Control Plane"
        ],
        "summary": "Change my password",
        "description": "The caller's own password, with the current one: 8 to 256 characters, not the default. The first admin's is stored in the sign-in settings (console.password_hash), anyone else's in the user store. The caller's other sessions end and a fresh token is answered. 400 not_a_user for a credential that is not a user's.",
        "operationId": "changeMyPassword",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "current_password",
                  "new_password"
                ],
                "properties": {
                  "current_password": {
                    "type": "string"
                  },
                  "new_password": {
                    "type": "string",
                    "minLength": 8,
                    "maxLength": 256
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Changed",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "changed": {
                      "type": "boolean"
                    },
                    "user": {
                      "type": "string"
                    },
                    "signed_out": {
                      "type": "integer"
                    },
                    "token": {
                      "type": "string"
                    },
                    "expires_at": {
                      "type": "string",
                      "format": "date-time"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "The new password breaks a rule, or not a user"
          },
          "403": {
            "description": "The current password is wrong"
          },
          "404": {
            "description": "Not in password mode (or shared mode)"
          },
          "429": {
            "description": "Too many wrong current passwords"
          }
        },
        "x-rustybin-permission": "signed in"
      }
    },
    "/_rustybin/join": {
      "post": {
        "tags": [
          "Control Plane"
        ],
        "summary": "Accept an invitation",
        "description": "The token of an invitation link (/ui/#/join/<token>) and the new password (8 to 256 characters, not the default). One use, 72 hours. Answers a sign-in token for the user, so the person is signed in. Never behind control-plane auth; rate limited per client address (5 failures a minute) and for every address together (20 a minute, the invitations' own lane: failures here never hold back a sign-in).",
        "operationId": "acceptInvitation",
        "security": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "token",
                  "password"
                ],
                "properties": {
                  "token": {
                    "type": "string",
                    "description": "rbi_ plus 43 base64url characters"
                  },
                  "password": {
                    "type": "string",
                    "minLength": 8,
                    "maxLength": 256
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Joined and signed in",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "token": {
                      "type": "string",
                      "description": "A control token (HS256 JWT): send it as Authorization: Bearer"
                    },
                    "token_type": {
                      "type": "string",
                      "enum": [
                        "Bearer"
                      ]
                    },
                    "expires_in": {
                      "type": "integer"
                    },
                    "expires_at": {
                      "type": "string",
                      "format": "date-time"
                    },
                    "scopes": {
                      "type": "array",
                      "items": {
                        "type": "string"
                      }
                    },
                    "user": {
                      "type": "string"
                    },
                    "user_id": {
                      "type": "string",
                      "description": "The user's id in the user store (usr_ plus 16 hex)"
                    },
                    "default_password": {
                      "type": "boolean",
                      "description": "The instance still signs in with the default password"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "The password breaks a rule (the invitation is not used)"
          },
          "401": {
            "description": "Not a valid invitation (reason invalid_invitation)"
          },
          "404": {
            "description": "Not in password mode (or shared mode)"
          },
          "429": {
            "description": "Too many attempts from this address (Retry-After)"
          }
        },
        "x-rustybin-permission": "open"
      }
    },
    "/_rustybin/users": {
      "get": {
        "tags": [
          "Control Plane"
        ],
        "summary": "Users",
        "operationId": "listUsers",
        "description": "Every user with roles, status, the last sign-in, the open invitation (never its link) and the sessions listed. Password sign-in only.",
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "users": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "id": {
                            "type": "string",
                            "description": "usr_ plus 16 hex"
                          },
                          "name": {
                            "type": "string",
                            "description": "The sign-in name"
                          },
                          "display_name": {
                            "type": "string"
                          },
                          "email": {
                            "type": [
                              "string",
                              "null"
                            ]
                          },
                          "roles": {
                            "type": "array",
                            "items": {
                              "type": "string"
                            }
                          },
                          "disabled": {
                            "type": "boolean"
                          },
                          "status": {
                            "type": "string",
                            "enum": [
                              "active",
                              "invited",
                              "disabled"
                            ]
                          },
                          "source": {
                            "type": "string",
                            "enum": [
                              "password",
                              "sso",
                              "document"
                            ]
                          },
                          "created_at": {
                            "type": "string",
                            "format": "date-time"
                          },
                          "last_sign_in": {
                            "type": [
                              "string",
                              "null"
                            ],
                            "format": "date-time"
                          },
                          "invitation": {
                            "type": [
                              "object",
                              "null"
                            ],
                            "description": "The open invitation (never its link)",
                            "properties": {
                              "created_at": {
                                "type": "string",
                                "format": "date-time"
                              },
                              "expires_at": {
                                "type": "string",
                                "format": "date-time"
                              },
                              "by": {
                                "type": "string"
                              },
                              "reset": {
                                "type": "boolean"
                              }
                            }
                          },
                          "sessions": {
                            "type": "integer",
                            "description": "Sign-in sessions listed for the user"
                          },
                          "first_admin": {
                            "type": "boolean",
                            "description": "User one: the console user of the sign-in settings"
                          },
                          "projects": {
                            "type": "array",
                            "description": "The user's roles in projects (sso: given by a single sign-on group)",
                            "items": {
                              "type": "object",
                              "properties": {
                                "project": {
                                  "type": "string"
                                },
                                "roles": {
                                  "type": "array",
                                  "items": {
                                    "type": "string"
                                  }
                                },
                                "sso": {
                                  "type": "boolean"
                                }
                              }
                            }
                          }
                        }
                      }
                    },
                    "count": {
                      "type": "integer"
                    },
                    "capacity": {
                      "type": "integer"
                    },
                    "open_invitations": {
                      "type": "integer"
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "No such user, or not in password mode"
          },
          "403": {
            "description": "permission_required: the caller lacks users.read"
          }
        },
        "x-rustybin-permission": "users.read"
      },
      "post": {
        "tags": [
          "Control Plane"
        ],
        "summary": "Invite a user",
        "operationId": "inviteUser",
        "description": "Creates the user, invited (disabled until they accept), and answers the one-time link (72 hours, shown once, kept only as a SHA-256). The person opens it and sets their own password: nobody else ever sees or types it.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "name"
                ],
                "properties": {
                  "name": {
                    "type": "string",
                    "description": "The sign-in name: letters, digits and . _ @ -, at most 64"
                  },
                  "display_name": {
                    "type": "string"
                  },
                  "email": {
                    "type": "string"
                  },
                  "roles": {
                    "type": "array",
                    "items": {
                      "type": "string"
                    },
                    "description": "Instance roles: at least one, unless projects gives roles in a project"
                  },
                  "projects": {
                    "type": "array",
                    "description": "Roles in projects (step 11)",
                    "items": {
                      "type": "object",
                      "required": [
                        "project",
                        "roles"
                      ],
                      "properties": {
                        "project": {
                          "type": "string"
                        },
                        "roles": {
                          "type": "array",
                          "items": {
                            "type": "string"
                          },
                          "minItems": 1
                        }
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Invited",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "user": {
                      "type": "object",
                      "properties": {
                        "id": {
                          "type": "string",
                          "description": "usr_ plus 16 hex"
                        },
                        "name": {
                          "type": "string",
                          "description": "The sign-in name"
                        },
                        "display_name": {
                          "type": "string"
                        },
                        "email": {
                          "type": [
                            "string",
                            "null"
                          ]
                        },
                        "roles": {
                          "type": "array",
                          "items": {
                            "type": "string"
                          }
                        },
                        "disabled": {
                          "type": "boolean"
                        },
                        "status": {
                          "type": "string",
                          "enum": [
                            "active",
                            "invited",
                            "disabled"
                          ]
                        },
                        "source": {
                          "type": "string",
                          "enum": [
                            "password",
                            "sso",
                            "document"
                          ]
                        },
                        "created_at": {
                          "type": "string",
                          "format": "date-time"
                        },
                        "last_sign_in": {
                          "type": [
                            "string",
                            "null"
                          ],
                          "format": "date-time"
                        },
                        "invitation": {
                          "type": [
                            "object",
                            "null"
                          ],
                          "description": "The open invitation (never its link)",
                          "properties": {
                            "created_at": {
                              "type": "string",
                              "format": "date-time"
                            },
                            "expires_at": {
                              "type": "string",
                              "format": "date-time"
                            },
                            "by": {
                              "type": "string"
                            },
                            "reset": {
                              "type": "boolean"
                            }
                          }
                        },
                        "sessions": {
                          "type": "integer",
                          "description": "Sign-in sessions listed for the user"
                        },
                        "first_admin": {
                          "type": "boolean",
                          "description": "User one: the console user of the sign-in settings"
                        },
                        "projects": {
                          "type": "array",
                          "description": "The user's roles in projects (sso: given by a single sign-on group)",
                          "items": {
                            "type": "object",
                            "properties": {
                              "project": {
                                "type": "string"
                              },
                              "roles": {
                                "type": "array",
                                "items": {
                                  "type": "string"
                                }
                              },
                              "sso": {
                                "type": "boolean"
                              }
                            }
                          }
                        }
                      }
                    },
                    "invitation": {
                      "type": "object",
                      "properties": {
                        "url": {
                          "type": "string",
                          "description": "<instance>/ui/#/join/<token>: send it to the person; shown once"
                        },
                        "token": {
                          "type": "string",
                          "description": "rbi_ plus 43 base64url characters (32 random bytes)"
                        },
                        "expires_at": {
                          "type": "string",
                          "format": "date-time"
                        },
                        "reset": {
                          "type": "boolean"
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Invalid"
          },
          "404": {
            "description": "No such user, or not in password mode"
          },
          "409": {
            "description": "A guard rail (reason last_admin, first_admin, invited, role_in_use, full)"
          },
          "403": {
            "description": "permission_required: the caller lacks users.manage"
          }
        },
        "x-rustybin-permission": "users.manage"
      }
    },
    "/_rustybin/users/{id}": {
      "get": {
        "tags": [
          "Control Plane"
        ],
        "summary": "A user",
        "operationId": "getUser",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "A user id or sign-in name",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "id": {
                      "type": "string",
                      "description": "usr_ plus 16 hex"
                    },
                    "name": {
                      "type": "string",
                      "description": "The sign-in name"
                    },
                    "display_name": {
                      "type": "string"
                    },
                    "email": {
                      "type": [
                        "string",
                        "null"
                      ]
                    },
                    "roles": {
                      "type": "array",
                      "items": {
                        "type": "string"
                      }
                    },
                    "disabled": {
                      "type": "boolean"
                    },
                    "status": {
                      "type": "string",
                      "enum": [
                        "active",
                        "invited",
                        "disabled"
                      ]
                    },
                    "source": {
                      "type": "string",
                      "enum": [
                        "password",
                        "sso",
                        "document"
                      ]
                    },
                    "created_at": {
                      "type": "string",
                      "format": "date-time"
                    },
                    "last_sign_in": {
                      "type": [
                        "string",
                        "null"
                      ],
                      "format": "date-time"
                    },
                    "invitation": {
                      "type": [
                        "object",
                        "null"
                      ],
                      "description": "The open invitation (never its link)",
                      "properties": {
                        "created_at": {
                          "type": "string",
                          "format": "date-time"
                        },
                        "expires_at": {
                          "type": "string",
                          "format": "date-time"
                        },
                        "by": {
                          "type": "string"
                        },
                        "reset": {
                          "type": "boolean"
                        }
                      }
                    },
                    "sessions": {
                      "type": "integer",
                      "description": "Sign-in sessions listed for the user"
                    },
                    "first_admin": {
                      "type": "boolean",
                      "description": "User one: the console user of the sign-in settings"
                    },
                    "projects": {
                      "type": "array",
                      "description": "The user's roles in projects (sso: given by a single sign-on group)",
                      "items": {
                        "type": "object",
                        "properties": {
                          "project": {
                            "type": "string"
                          },
                          "roles": {
                            "type": "array",
                            "items": {
                              "type": "string"
                            }
                          },
                          "sso": {
                            "type": "boolean"
                          }
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "No such user, or not in password mode"
          },
          "403": {
            "description": "permission_required: the caller lacks users.read"
          }
        },
        "x-rustybin-permission": "users.read"
      },
      "patch": {
        "tags": [
          "Control Plane"
        ],
        "summary": "Change a user",
        "operationId": "updateUser",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "A user id or sign-in name",
            "schema": {
              "type": "string"
            }
          }
        ],
        "description": "Roles, display name, email (null clears it), disabled. Disabling ends the user's sessions. Nobody changes their own roles; the last enabled admin stays.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "roles": {
                    "type": "array",
                    "items": {
                      "type": "string"
                    },
                    "minItems": 1
                  },
                  "display_name": {
                    "type": "string"
                  },
                  "email": {
                    "type": [
                      "string",
                      "null"
                    ]
                  },
                  "disabled": {
                    "type": "boolean"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "id": {
                      "type": "string",
                      "description": "usr_ plus 16 hex"
                    },
                    "name": {
                      "type": "string",
                      "description": "The sign-in name"
                    },
                    "display_name": {
                      "type": "string"
                    },
                    "email": {
                      "type": [
                        "string",
                        "null"
                      ]
                    },
                    "roles": {
                      "type": "array",
                      "items": {
                        "type": "string"
                      }
                    },
                    "disabled": {
                      "type": "boolean"
                    },
                    "status": {
                      "type": "string",
                      "enum": [
                        "active",
                        "invited",
                        "disabled"
                      ]
                    },
                    "source": {
                      "type": "string",
                      "enum": [
                        "password",
                        "sso",
                        "document"
                      ]
                    },
                    "created_at": {
                      "type": "string",
                      "format": "date-time"
                    },
                    "last_sign_in": {
                      "type": [
                        "string",
                        "null"
                      ],
                      "format": "date-time"
                    },
                    "invitation": {
                      "type": [
                        "object",
                        "null"
                      ],
                      "description": "The open invitation (never its link)",
                      "properties": {
                        "created_at": {
                          "type": "string",
                          "format": "date-time"
                        },
                        "expires_at": {
                          "type": "string",
                          "format": "date-time"
                        },
                        "by": {
                          "type": "string"
                        },
                        "reset": {
                          "type": "boolean"
                        }
                      }
                    },
                    "sessions": {
                      "type": "integer",
                      "description": "Sign-in sessions listed for the user"
                    },
                    "first_admin": {
                      "type": "boolean",
                      "description": "User one: the console user of the sign-in settings"
                    },
                    "projects": {
                      "type": "array",
                      "description": "The user's roles in projects (sso: given by a single sign-on group)",
                      "items": {
                        "type": "object",
                        "properties": {
                          "project": {
                            "type": "string"
                          },
                          "roles": {
                            "type": "array",
                            "items": {
                              "type": "string"
                            }
                          },
                          "sso": {
                            "type": "boolean"
                          }
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Invalid"
          },
          "404": {
            "description": "No such user, or not in password mode"
          },
          "409": {
            "description": "A guard rail (reason last_admin, first_admin, invited, role_in_use, full)"
          },
          "403": {
            "description": "permission_required: the caller lacks users.manage"
          }
        },
        "x-rustybin-permission": "users.manage"
      },
      "delete": {
        "tags": [
          "Control Plane"
        ],
        "summary": "Delete a user",
        "operationId": "deleteUser",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "A user id or sign-in name",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "deleted": {
                      "type": "string"
                    },
                    "sessions_ended": {
                      "type": "integer"
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "No such user, or not in password mode"
          },
          "409": {
            "description": "A guard rail (reason last_admin, first_admin, invited, role_in_use, full)"
          },
          "403": {
            "description": "permission_required: the caller lacks users.manage"
          }
        },
        "x-rustybin-permission": "users.manage"
      }
    },
    "/_rustybin/users/{id}/invite": {
      "post": {
        "tags": [
          "Control Plane"
        ],
        "summary": "A new invitation link (a password reset)",
        "operationId": "reinviteUser",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "A user id or sign-in name",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "201": {
            "description": "A new link",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "user": {
                      "type": "object",
                      "properties": {
                        "id": {
                          "type": "string",
                          "description": "usr_ plus 16 hex"
                        },
                        "name": {
                          "type": "string",
                          "description": "The sign-in name"
                        },
                        "display_name": {
                          "type": "string"
                        },
                        "email": {
                          "type": [
                            "string",
                            "null"
                          ]
                        },
                        "roles": {
                          "type": "array",
                          "items": {
                            "type": "string"
                          }
                        },
                        "disabled": {
                          "type": "boolean"
                        },
                        "status": {
                          "type": "string",
                          "enum": [
                            "active",
                            "invited",
                            "disabled"
                          ]
                        },
                        "source": {
                          "type": "string",
                          "enum": [
                            "password",
                            "sso",
                            "document"
                          ]
                        },
                        "created_at": {
                          "type": "string",
                          "format": "date-time"
                        },
                        "last_sign_in": {
                          "type": [
                            "string",
                            "null"
                          ],
                          "format": "date-time"
                        },
                        "invitation": {
                          "type": [
                            "object",
                            "null"
                          ],
                          "description": "The open invitation (never its link)",
                          "properties": {
                            "created_at": {
                              "type": "string",
                              "format": "date-time"
                            },
                            "expires_at": {
                              "type": "string",
                              "format": "date-time"
                            },
                            "by": {
                              "type": "string"
                            },
                            "reset": {
                              "type": "boolean"
                            }
                          }
                        },
                        "sessions": {
                          "type": "integer",
                          "description": "Sign-in sessions listed for the user"
                        },
                        "first_admin": {
                          "type": "boolean",
                          "description": "User one: the console user of the sign-in settings"
                        },
                        "projects": {
                          "type": "array",
                          "description": "The user's roles in projects (sso: given by a single sign-on group)",
                          "items": {
                            "type": "object",
                            "properties": {
                              "project": {
                                "type": "string"
                              },
                              "roles": {
                                "type": "array",
                                "items": {
                                  "type": "string"
                                }
                              },
                              "sso": {
                                "type": "boolean"
                              }
                            }
                          }
                        }
                      }
                    },
                    "invitation": {
                      "type": "object",
                      "properties": {
                        "url": {
                          "type": "string",
                          "description": "<instance>/ui/#/join/<token>: send it to the person; shown once"
                        },
                        "token": {
                          "type": "string",
                          "description": "rbi_ plus 43 base64url characters (32 random bytes)"
                        },
                        "expires_at": {
                          "type": "string",
                          "format": "date-time"
                        },
                        "reset": {
                          "type": "boolean"
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "No such user, or not in password mode"
          },
          "409": {
            "description": "A guard rail (reason last_admin, first_admin, invited, role_in_use, full)"
          },
          "403": {
            "description": "permission_required: the caller lacks users.manage"
          }
        },
        "x-rustybin-permission": "users.manage"
      }
    },
    "/_rustybin/users/{id}/sessions": {
      "get": {
        "tags": [
          "Control Plane"
        ],
        "summary": "A user's sessions",
        "operationId": "listUserSessions",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "A user id or sign-in name",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "count": {
                      "type": "integer"
                    },
                    "sessions": {
                      "type": "array",
                      "items": {
                        "type": "object"
                      }
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "No such user, or not in password mode"
          },
          "403": {
            "description": "permission_required: the caller lacks users.read"
          }
        },
        "x-rustybin-permission": "users.read"
      },
      "delete": {
        "tags": [
          "Control Plane"
        ],
        "summary": "Sign a user out everywhere",
        "operationId": "endUserSessions",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "A user id or sign-in name",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "ended": {
                      "type": "integer"
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "No such user, or not in password mode"
          },
          "403": {
            "description": "permission_required: the caller lacks users.manage"
          }
        },
        "x-rustybin-permission": "users.manage"
      }
    },
    "/_rustybin/roles": {
      "get": {
        "tags": [
          "Control Plane"
        ],
        "summary": "Roles",
        "operationId": "listRoles",
        "description": "The built-in roles, then the custom ones, each with its permissions and how many users hold it, and the permission table (name, group, summary).",
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "roles": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "name": {
                            "type": "string"
                          },
                          "description": {
                            "type": "string"
                          },
                          "built_in": {
                            "type": "boolean"
                          },
                          "privileged": {
                            "type": "boolean",
                            "description": "Grants users.manage or settings.security"
                          },
                          "permissions": {
                            "type": "array",
                            "items": {
                              "type": "string"
                            }
                          },
                          "users": {
                            "type": "integer",
                            "description": "Users holding it"
                          }
                        }
                      }
                    },
                    "permissions": {
                      "type": "array",
                      "items": {
                        "type": "object"
                      }
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "permission_required: the caller lacks users.read"
          }
        },
        "x-rustybin-permission": "users.read"
      },
      "post": {
        "tags": [
          "Control Plane"
        ],
        "summary": "Create a custom role",
        "operationId": "createRole",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "permissions"
                ],
                "properties": {
                  "name": {
                    "type": "string",
                    "description": "1 to 40 lower case letters, digits, _ and -, starting with a letter; not a built-in name"
                  },
                  "description": {
                    "type": "string",
                    "maxLength": 200
                  },
                  "permissions": {
                    "type": "array",
                    "items": {
                      "type": "string"
                    },
                    "minItems": 1,
                    "description": "Permission names (GET /_rustybin/roles lists them)"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "name": {
                      "type": "string"
                    },
                    "description": {
                      "type": "string"
                    },
                    "built_in": {
                      "type": "boolean"
                    },
                    "privileged": {
                      "type": "boolean",
                      "description": "Grants users.manage or settings.security"
                    },
                    "permissions": {
                      "type": "array",
                      "items": {
                        "type": "string"
                      }
                    },
                    "users": {
                      "type": "integer",
                      "description": "Users holding it"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Invalid, or a built-in name"
          },
          "409": {
            "description": "A role of that name exists, or the cap"
          },
          "403": {
            "description": "permission_required: the caller lacks users.manage"
          }
        },
        "x-rustybin-permission": "users.manage"
      }
    },
    "/_rustybin/roles/{name}": {
      "get": {
        "tags": [
          "Control Plane"
        ],
        "summary": "A role",
        "operationId": "getRole",
        "parameters": [
          {
            "name": "name",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "name": {
                      "type": "string"
                    },
                    "description": {
                      "type": "string"
                    },
                    "built_in": {
                      "type": "boolean"
                    },
                    "privileged": {
                      "type": "boolean",
                      "description": "Grants users.manage or settings.security"
                    },
                    "permissions": {
                      "type": "array",
                      "items": {
                        "type": "string"
                      }
                    },
                    "users": {
                      "type": "integer",
                      "description": "Users holding it"
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "No such role"
          },
          "403": {
            "description": "permission_required: the caller lacks users.read"
          }
        },
        "x-rustybin-permission": "users.read"
      },
      "put": {
        "tags": [
          "Control Plane"
        ],
        "summary": "Create or change a custom role",
        "operationId": "putRole",
        "parameters": [
          {
            "name": "name",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "permissions"
                ],
                "properties": {
                  "name": {
                    "type": "string",
                    "description": "1 to 40 lower case letters, digits, _ and -, starting with a letter; not a built-in name"
                  },
                  "description": {
                    "type": "string",
                    "maxLength": 200
                  },
                  "permissions": {
                    "type": "array",
                    "items": {
                      "type": "string"
                    },
                    "minItems": 1,
                    "description": "Permission names (GET /_rustybin/roles lists them)"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "name": {
                      "type": "string"
                    },
                    "description": {
                      "type": "string"
                    },
                    "built_in": {
                      "type": "boolean"
                    },
                    "privileged": {
                      "type": "boolean",
                      "description": "Grants users.manage or settings.security"
                    },
                    "permissions": {
                      "type": "array",
                      "items": {
                        "type": "string"
                      }
                    },
                    "users": {
                      "type": "integer",
                      "description": "Users holding it"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Invalid, or a built-in role"
          },
          "403": {
            "description": "permission_required: the caller lacks users.manage"
          }
        },
        "x-rustybin-permission": "users.manage"
      },
      "delete": {
        "tags": [
          "Control Plane"
        ],
        "summary": "Delete a custom role",
        "operationId": "deleteRole",
        "parameters": [
          {
            "name": "name",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "deleted": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "No such custom role"
          },
          "409": {
            "description": "Somebody holds it (role_in_use)"
          },
          "403": {
            "description": "permission_required: the caller lacks users.manage"
          }
        },
        "x-rustybin-permission": "users.manage"
      }
    },
    "/_rustybin/me": {
      "get": {
        "tags": [
          "Control Plane"
        ],
        "summary": "My account",
        "operationId": "getMe",
        "description": "The caller's own user, roles, permissions and sessions count. 400 not_a_user for a credential that is not a user's.",
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "id": {
                      "type": "string",
                      "description": "usr_ plus 16 hex"
                    },
                    "name": {
                      "type": "string",
                      "description": "The sign-in name"
                    },
                    "display_name": {
                      "type": "string"
                    },
                    "email": {
                      "type": [
                        "string",
                        "null"
                      ]
                    },
                    "roles": {
                      "type": "array",
                      "items": {
                        "type": "string"
                      }
                    },
                    "disabled": {
                      "type": "boolean"
                    },
                    "status": {
                      "type": "string",
                      "enum": [
                        "active",
                        "invited",
                        "disabled"
                      ]
                    },
                    "source": {
                      "type": "string",
                      "enum": [
                        "password",
                        "sso",
                        "document"
                      ]
                    },
                    "created_at": {
                      "type": "string",
                      "format": "date-time"
                    },
                    "last_sign_in": {
                      "type": [
                        "string",
                        "null"
                      ],
                      "format": "date-time"
                    },
                    "invitation": {
                      "type": [
                        "object",
                        "null"
                      ],
                      "description": "The open invitation (never its link)",
                      "properties": {
                        "created_at": {
                          "type": "string",
                          "format": "date-time"
                        },
                        "expires_at": {
                          "type": "string",
                          "format": "date-time"
                        },
                        "by": {
                          "type": "string"
                        },
                        "reset": {
                          "type": "boolean"
                        }
                      }
                    },
                    "sessions": {
                      "type": "integer",
                      "description": "Sign-in sessions listed for the user"
                    },
                    "first_admin": {
                      "type": "boolean",
                      "description": "User one: the console user of the sign-in settings"
                    },
                    "projects": {
                      "type": "array",
                      "description": "The user's roles in projects (sso: given by a single sign-on group)",
                      "items": {
                        "type": "object",
                        "properties": {
                          "project": {
                            "type": "string"
                          },
                          "roles": {
                            "type": "array",
                            "items": {
                              "type": "string"
                            }
                          },
                          "sso": {
                            "type": "boolean"
                          }
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Not a user (reason not_a_user)"
          },
          "404": {
            "description": "Not in password mode"
          }
        },
        "x-rustybin-permission": "signed in"
      },
      "patch": {
        "tags": [
          "Control Plane"
        ],
        "summary": "Change my display name or email",
        "operationId": "updateMe",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "display_name": {
                    "type": "string"
                  },
                  "email": {
                    "type": [
                      "string",
                      "null"
                    ]
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "id": {
                      "type": "string",
                      "description": "usr_ plus 16 hex"
                    },
                    "name": {
                      "type": "string",
                      "description": "The sign-in name"
                    },
                    "display_name": {
                      "type": "string"
                    },
                    "email": {
                      "type": [
                        "string",
                        "null"
                      ]
                    },
                    "roles": {
                      "type": "array",
                      "items": {
                        "type": "string"
                      }
                    },
                    "disabled": {
                      "type": "boolean"
                    },
                    "status": {
                      "type": "string",
                      "enum": [
                        "active",
                        "invited",
                        "disabled"
                      ]
                    },
                    "source": {
                      "type": "string",
                      "enum": [
                        "password",
                        "sso",
                        "document"
                      ]
                    },
                    "created_at": {
                      "type": "string",
                      "format": "date-time"
                    },
                    "last_sign_in": {
                      "type": [
                        "string",
                        "null"
                      ],
                      "format": "date-time"
                    },
                    "invitation": {
                      "type": [
                        "object",
                        "null"
                      ],
                      "description": "The open invitation (never its link)",
                      "properties": {
                        "created_at": {
                          "type": "string",
                          "format": "date-time"
                        },
                        "expires_at": {
                          "type": "string",
                          "format": "date-time"
                        },
                        "by": {
                          "type": "string"
                        },
                        "reset": {
                          "type": "boolean"
                        }
                      }
                    },
                    "sessions": {
                      "type": "integer",
                      "description": "Sign-in sessions listed for the user"
                    },
                    "first_admin": {
                      "type": "boolean",
                      "description": "User one: the console user of the sign-in settings"
                    },
                    "projects": {
                      "type": "array",
                      "description": "The user's roles in projects (sso: given by a single sign-on group)",
                      "items": {
                        "type": "object",
                        "properties": {
                          "project": {
                            "type": "string"
                          },
                          "roles": {
                            "type": "array",
                            "items": {
                              "type": "string"
                            }
                          },
                          "sso": {
                            "type": "boolean"
                          }
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Invalid, or not a user"
          },
          "404": {
            "description": "Not in password mode"
          }
        },
        "x-rustybin-permission": "signed in"
      }
    },
    "/_rustybin/me/sessions": {
      "get": {
        "tags": [
          "Control Plane"
        ],
        "summary": "My sessions",
        "operationId": "listMySessions",
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "count": {
                      "type": "integer"
                    },
                    "sessions": {
                      "type": "array",
                      "items": {
                        "type": "object"
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Not a user"
          },
          "404": {
            "description": "Not in password mode"
          }
        },
        "x-rustybin-permission": "signed in"
      },
      "delete": {
        "tags": [
          "Control Plane"
        ],
        "summary": "Sign myself out everywhere",
        "operationId": "endMySessions",
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "ended": {
                      "type": "integer"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Not a user"
          },
          "404": {
            "description": "Not in password mode"
          }
        },
        "x-rustybin-permission": "signed in"
      }
    },
    "/_rustybin/me/sessions/{id}": {
      "delete": {
        "tags": [
          "Control Plane"
        ],
        "summary": "End one of my sessions",
        "operationId": "endMySession",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "ended": {
                      "type": "boolean"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Not a user"
          },
          "404": {
            "description": "Not in password mode"
          }
        },
        "x-rustybin-permission": "signed in"
      }
    },
    "/_rustybin/projects": {
      "get": {
        "tags": [
          "Control Plane"
        ],
        "summary": "Projects",
        "operationId": "listProjects",
        "responses": {
          "200": {
            "description": "The projects the caller may see",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "count": {
                      "type": "integer"
                    },
                    "capacity": {
                      "type": "integer"
                    },
                    "projects": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "name": {
                            "type": "string"
                          },
                          "description": {
                            "type": "string"
                          },
                          "created_at": {
                            "type": "string",
                            "format": "date-time"
                          },
                          "member_count": {
                            "type": "integer"
                          },
                          "members": {
                            "type": "array",
                            "description": "With users.read",
                            "items": {
                              "type": "object",
                              "properties": {
                                "user": {
                                  "type": [
                                    "string",
                                    "null"
                                  ]
                                },
                                "user_id": {
                                  "type": "string"
                                },
                                "roles": {
                                  "type": "array",
                                  "items": {
                                    "type": "string"
                                  }
                                }
                              }
                            }
                          },
                          "your_roles": {
                            "type": "array",
                            "items": {
                              "type": "string"
                            }
                          },
                          "your_permissions": {
                            "type": "array",
                            "items": {
                              "type": "string"
                            }
                          },
                          "resources": {
                            "type": "object",
                            "properties": {
                              "mocks": {
                                "type": "array",
                                "items": {
                                  "type": "string"
                                }
                              },
                              "tests": {
                                "type": "array",
                                "items": {
                                  "type": "string"
                                }
                              },
                              "checkpoints": {
                                "type": "array",
                                "items": {
                                  "type": "string"
                                }
                              }
                            }
                          }
                        }
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "x-rustybin-permission": "signed in"
      }
    },
    "/_rustybin/projects/{name}": {
      "get": {
        "tags": [
          "Control Plane"
        ],
        "summary": "A project",
        "operationId": "getProject",
        "parameters": [
          {
            "name": "name",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "The project",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "name": {
                      "type": "string"
                    },
                    "description": {
                      "type": "string"
                    },
                    "created_at": {
                      "type": "string",
                      "format": "date-time"
                    },
                    "member_count": {
                      "type": "integer"
                    },
                    "members": {
                      "type": "array",
                      "description": "With users.read",
                      "items": {
                        "type": "object",
                        "properties": {
                          "user": {
                            "type": [
                              "string",
                              "null"
                            ]
                          },
                          "user_id": {
                            "type": "string"
                          },
                          "roles": {
                            "type": "array",
                            "items": {
                              "type": "string"
                            }
                          }
                        }
                      }
                    },
                    "your_roles": {
                      "type": "array",
                      "items": {
                        "type": "string"
                      }
                    },
                    "your_permissions": {
                      "type": "array",
                      "items": {
                        "type": "string"
                      }
                    },
                    "resources": {
                      "type": "object",
                      "properties": {
                        "mocks": {
                          "type": "array",
                          "items": {
                            "type": "string"
                          }
                        },
                        "tests": {
                          "type": "array",
                          "items": {
                            "type": "string"
                          }
                        },
                        "checkpoints": {
                          "type": "array",
                          "items": {
                            "type": "string"
                          }
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "No such project, or one the caller may not see"
          }
        },
        "x-rustybin-permission": "signed in"
      },
      "put": {
        "tags": [
          "Control Plane"
        ],
        "summary": "Create or change a project",
        "operationId": "saveProject",
        "parameters": [
          {
            "name": "name",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": false,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "additionalProperties": false,
                "properties": {
                  "description": {
                    "type": "string",
                    "maxLength": 200
                  },
                  "members": {
                    "type": "array",
                    "description": "The whole member list",
                    "items": {
                      "type": "object",
                      "required": [
                        "user",
                        "roles"
                      ],
                      "additionalProperties": false,
                      "properties": {
                        "user": {
                          "type": "string",
                          "description": "An id or a sign-in name"
                        },
                        "roles": {
                          "type": "array",
                          "items": {
                            "type": "string"
                          }
                        }
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Changed",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "name": {
                      "type": "string"
                    },
                    "description": {
                      "type": "string"
                    },
                    "created_at": {
                      "type": "string",
                      "format": "date-time"
                    },
                    "member_count": {
                      "type": "integer"
                    },
                    "members": {
                      "type": "array",
                      "description": "With users.read",
                      "items": {
                        "type": "object",
                        "properties": {
                          "user": {
                            "type": [
                              "string",
                              "null"
                            ]
                          },
                          "user_id": {
                            "type": "string"
                          },
                          "roles": {
                            "type": "array",
                            "items": {
                              "type": "string"
                            }
                          }
                        }
                      }
                    },
                    "your_roles": {
                      "type": "array",
                      "items": {
                        "type": "string"
                      }
                    },
                    "your_permissions": {
                      "type": "array",
                      "items": {
                        "type": "string"
                      }
                    },
                    "resources": {
                      "type": "object",
                      "properties": {
                        "mocks": {
                          "type": "array",
                          "items": {
                            "type": "string"
                          }
                        },
                        "tests": {
                          "type": "array",
                          "items": {
                            "type": "string"
                          }
                        },
                        "checkpoints": {
                          "type": "array",
                          "items": {
                            "type": "string"
                          }
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "201": {
            "description": "Created",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "name": {
                      "type": "string"
                    },
                    "description": {
                      "type": "string"
                    },
                    "created_at": {
                      "type": "string",
                      "format": "date-time"
                    },
                    "member_count": {
                      "type": "integer"
                    },
                    "members": {
                      "type": "array",
                      "description": "With users.read",
                      "items": {
                        "type": "object",
                        "properties": {
                          "user": {
                            "type": [
                              "string",
                              "null"
                            ]
                          },
                          "user_id": {
                            "type": "string"
                          },
                          "roles": {
                            "type": "array",
                            "items": {
                              "type": "string"
                            }
                          }
                        }
                      }
                    },
                    "your_roles": {
                      "type": "array",
                      "items": {
                        "type": "string"
                      }
                    },
                    "your_permissions": {
                      "type": "array",
                      "items": {
                        "type": "string"
                      }
                    },
                    "resources": {
                      "type": "object",
                      "properties": {
                        "mocks": {
                          "type": "array",
                          "items": {
                            "type": "string"
                          }
                        },
                        "tests": {
                          "type": "array",
                          "items": {
                            "type": "string"
                          }
                        },
                        "checkpoints": {
                          "type": "array",
                          "items": {
                            "type": "string"
                          }
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "An invalid name, description or member"
          },
          "403": {
            "description": "users.manage, own_roles, or a role beyond the caller's permissions in the project"
          }
        },
        "x-rustybin-permission": "users.manage"
      },
      "delete": {
        "tags": [
          "Control Plane"
        ],
        "summary": "Delete a project",
        "operationId": "deleteProject",
        "parameters": [
          {
            "name": "name",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "move_to",
            "in": "query",
            "required": false,
            "description": "Where its mocks, saved tests and checkpoints go: another project, or instance",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Deleted (and what moved)",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "404": {
            "description": "No such project"
          },
          "409": {
            "description": "not_empty: the project holds resources and no move_to was given"
          },
          "403": {
            "description": "permission_required: the caller lacks users.manage"
          }
        },
        "x-rustybin-permission": "users.manage"
      }
    },
    "/_rustybin/sso/status": {
      "get": {
        "tags": [
          "Control Plane"
        ],
        "summary": "Single sign-on status",
        "description": "What the sign-in screen needs: whether single sign-on is on and ready, the button's name and whether the password sign-in works. Never a secret; nothing is fetched. Open.",
        "operationId": "getSsoStatus",
        "security": [],
        "responses": {
          "200": {
            "description": "The status",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "enabled": {
                      "type": "boolean",
                      "description": "sso.enabled"
                    },
                    "ready": {
                      "type": "boolean",
                      "description": "Enabled, with the issuer and the client id set"
                    },
                    "name": {
                      "type": [
                        "string",
                        "null"
                      ],
                      "description": "The button's name: Sign in with <name>"
                    },
                    "password_sign_in": {
                      "type": "boolean",
                      "description": "The password sign-in works (off only while single sign-on is ready and sso.password_sign_in is off)"
                    },
                    "reason": {
                      "type": [
                        "string",
                        "null"
                      ],
                      "description": "Why it is not ready"
                    },
                    "start": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "Not in the password sign-in (RUSTYBIN_CONTROL_AUTH=password, outside shared mode)"
          }
        },
        "x-rustybin-permission": "open"
      }
    },
    "/_rustybin/sso/start": {
      "get": {
        "tags": [
          "Control Plane"
        ],
        "summary": "Start a single sign-on",
        "description": "Sends the browser to the identity provider's authorization endpoint (authorization code flow, PKCE S256, state, nonce). return_to: console, or an http:// address on a loopback host (the CLI). challenge: the S256 challenge of a verifier the client keeps. Open; at most 10 sign-ins under way per client address. A refusal goes back to return_to (the console's #/sso-error/<reason>, or the loopback address with error and error_description).",
        "operationId": "startSso",
        "security": [],
        "parameters": [
          {
            "name": "return_to",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "default": "console"
            }
          },
          {
            "name": "challenge",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string",
              "minLength": 43,
              "maxLength": 43
            }
          }
        ],
        "responses": {
          "302": {
            "description": "To the provider (or back to return_to with the refusal)"
          },
          "400": {
            "description": "return_to or challenge is not valid"
          },
          "404": {
            "description": "Not in the password sign-in (RUSTYBIN_CONTROL_AUTH=password, outside shared mode)"
          }
        },
        "x-rustybin-permission": "open"
      }
    },
    "/_rustybin/sso/callback": {
      "get": {
        "tags": [
          "Control Plane"
        ],
        "summary": "Single sign-on callback",
        "description": "The provider's redirect (register it as the client's redirect URI). The code is exchanged at the token endpoint, the ID token verified (issuer, audience, expiry, nonce; RS256 or ES256), the groups mapped to roles, the user linked or created, and the browser sent back to return_to with a one-time code (the console's #/sso/<code>, or ?code= on the loopback address). The provider's tokens are never kept. Open; throttled per client address like the sign-in. Refusal reasons: expired, denied, provider_error, invalid_id_token, domain_not_allowed, email_unverified, not_linked (no user this sign-in may use: a password account or another identity has the name, a user created ahead without the verified email, or none with sso.provision off; one reason for all, the detail is in the log), disabled, no_role, last_admin, rate_limited, busy.",
        "operationId": "ssoCallback",
        "security": [],
        "parameters": [
          {
            "name": "code",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "state",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "error",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "302": {
            "description": "Back to return_to, with the code or the refusal"
          },
          "400": {
            "description": "No sign-in under way for this state: an HTML page"
          },
          "404": {
            "description": "Not in the password sign-in (RUSTYBIN_CONTROL_AUTH=password, outside shared mode)"
          },
          "429": {
            "description": "Too many failures from this address: an HTML page"
          }
        },
        "x-rustybin-permission": "open"
      }
    },
    "/_rustybin/sso/token": {
      "post": {
        "tags": [
          "Control Plane"
        ],
        "summary": "Single sign-on: the code for a sign-in token",
        "description": "The one-time code the callback sent back and the PKCE verifier whose challenge started the sign-in. One use, two minutes. Answers the sign-in token (as POST /_rustybin/login). Open; throttled per client address.",
        "operationId": "ssoToken",
        "security": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "code",
                  "verifier"
                ],
                "properties": {
                  "code": {
                    "type": "string",
                    "description": "rbs_ plus 43 base64url characters"
                  },
                  "verifier": {
                    "type": "string",
                    "minLength": 43,
                    "maxLength": 128
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Signed in",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "token": {
                      "type": "string"
                    },
                    "token_type": {
                      "type": "string"
                    },
                    "expires_in": {
                      "type": "integer"
                    },
                    "expires_at": {
                      "type": "string",
                      "format": "date-time"
                    },
                    "user": {
                      "type": "string"
                    },
                    "user_id": {
                      "type": "string"
                    },
                    "obtained": {
                      "type": "string",
                      "enum": [
                        "sso"
                      ]
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Not a valid code for this verifier (reason invalid_code)"
          },
          "404": {
            "description": "Not in the password sign-in (RUSTYBIN_CONTROL_AUTH=password, outside shared mode)"
          },
          "429": {
            "description": "Too many failures from this address (Retry-After)"
          }
        },
        "x-rustybin-permission": "open"
      }
    },
    "/_rustybin/sso/test": {
      "post": {
        "tags": [
          "Control Plane"
        ],
        "summary": "Test single sign-on",
        "description": "Fetches the provider's discovery document and keys now (purpose sso of the outbound policy) and answers them, the redirect URI to register at the provider, the role map and the roles it names that do not exist. Never the client secret.",
        "operationId": "testSso",
        "responses": {
          "200": {
            "description": "The test (ok: false with error when the provider could not be read)",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "ok": {
                      "type": "boolean"
                    },
                    "error": {
                      "type": "string"
                    },
                    "redirect_uri": {
                      "type": "string"
                    },
                    "discovery": {
                      "type": "object"
                    },
                    "keys": {
                      "type": "array",
                      "items": {
                        "type": "object"
                      }
                    },
                    "unknown_roles": {
                      "type": "array",
                      "items": {
                        "type": "string"
                      }
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "Not in the password sign-in (RUSTYBIN_CONTROL_AUTH=password, outside shared mode)"
          },
          "403": {
            "description": "permission_required: the caller lacks settings.write"
          }
        },
        "x-rustybin-permission": "settings.write"
      }
    },
    "/_rustybin/assist": {
      "get": {
        "tags": [
          "Control Plane"
        ],
        "summary": "AI assist status",
        "description": "Whether AI assist is on (a provider and, except for the mock, a key), the effective models, the providers with their curated models and key state ({set, hint}), the tasks, the static suggestions per console view, the usage totals and the privacy note.",
        "operationId": "getAssist",
        "responses": {
          "200": {
            "description": "Status",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "403": {
            "description": "permission_required: the caller lacks assist.use"
          }
        },
        "x-rustybin-permission": "assist.use"
      }
    },
    "/_rustybin/assist/test": {
      "post": {
        "tags": [
          "Control Plane"
        ],
        "summary": "Test the AI provider",
        "description": "One short call (\"Reply with the single word OK\") to the configured provider: latency, model and the answer, or the provider's error. Admin.",
        "operationId": "testAssist",
        "responses": {
          "200": {
            "description": "The provider answered",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "ok": {
                      "type": "boolean"
                    },
                    "provider": {
                      "type": "string"
                    },
                    "model": {
                      "type": "string"
                    },
                    "latency_ms": {
                      "type": "integer"
                    },
                    "answer": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          },
          "502": {
            "description": "The provider refused or failed"
          },
          "503": {
            "description": "No provider or key is set"
          },
          "403": {
            "description": "permission_required: the caller lacks settings.write"
          }
        },
        "x-rustybin-permission": "settings.write"
      }
    },
    "/_rustybin/assist/run": {
      "post": {
        "tags": [
          "Control Plane"
        ],
        "summary": "Run an AI assist task",
        "description": "Runs a task with validated inputs. Streamed (stream true, or Accept: text/event-stream): events `sent` (what went to the provider, never the key), `delta` ({text}), `json` (the validated structured answer), `action` (an action a text answer proposed: open_view, copy, run_request), `usage` (tokens and estimated cost), `error`, `done`. Otherwise one JSON document {task, text, json, actions, usage, sent}. Tasks that change the instance need admin; the others the console scope.",
        "operationId": "runAssist",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "task",
                  "inputs"
                ],
                "properties": {
                  "task": {
                    "type": "string",
                    "enum": [
                      "free_answer",
                      "explain",
                      "suggest"
                    ]
                  },
                  "inputs": {
                    "type": "object"
                  },
                  "model": {
                    "type": "string",
                    "description": "A model id instead of the task's default"
                  },
                  "stream": {
                    "type": "boolean"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The answer (SSE or JSON)"
          },
          "400": {
            "description": "Invalid inputs"
          },
          "404": {
            "description": "Unknown task"
          },
          "422": {
            "description": "The inputs contain a stored secret or the admin token"
          },
          "429": {
            "description": "The caller's calls per minute (Retry-After)"
          },
          "502": {
            "description": "The provider failed (JSON mode)"
          },
          "503": {
            "description": "No provider or key is set"
          },
          "403": {
            "description": "permission_required: the caller lacks assist.use"
          }
        },
        "x-rustybin-permission": "assist.use"
      }
    },
    "/_rustybin/assist/models": {
      "get": {
        "tags": [
          "Control Plane"
        ],
        "summary": "AI assist models",
        "description": "The configured provider's models: the list last loaded from the provider (POST) merged with the curated table. Each model: id, name, tier (fast or capable), context window, output limit, list price per million tokens when known, note, whether it reasons before answering, whether it is curated and whether the provider listed it, the jobs it is chosen for and whether it is the model or the fast model. Plus the jobs: every task with its model and whether a setting chose it.",
        "operationId": "getAssistModels",
        "responses": {
          "200": {
            "description": "The models and the jobs",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "403": {
            "description": "permission_required: the caller lacks assist.use"
          }
        },
        "x-rustybin-permission": "assist.use"
      },
      "post": {
        "tags": [
          "Control Plane"
        ],
        "summary": "Load the provider's models",
        "description": "Asks the configured provider for its model list with the stored key (OpenAI and compatible endpoints: GET /models; Anthropic: GET /v1/models; Gemini: GET /v1beta/models, generateContent models only; the mock: its own), through the outbound policy, keeps at most 500 entries, and answers as GET does. Admin.",
        "operationId": "loadAssistModels",
        "responses": {
          "200": {
            "description": "The models and the jobs"
          },
          "502": {
            "description": "The provider refused or failed"
          },
          "503": {
            "description": "No provider or key is set"
          },
          "403": {
            "description": "permission_required: the caller lacks settings.write"
          }
        },
        "x-rustybin-permission": "settings.write"
      }
    },
    "/_rustybin/assist/usage": {
      "get": {
        "tags": [
          "Control Plane"
        ],
        "summary": "AI assist usage",
        "description": "Calls, errors, tokens and the estimated cost since start, in total, per provider and model, and per task. Admin.",
        "operationId": "getAssistUsage",
        "responses": {
          "200": {
            "description": "Usage",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "403": {
            "description": "permission_required: the caller lacks settings.read"
          }
        },
        "x-rustybin-permission": "settings.read"
      }
    },
    "/_rustybin/config": {
      "get": {
        "tags": [
          "Control Plane"
        ],
        "summary": "Effective configuration",
        "description": "The running configuration without secrets (the admin token is reported only as `admin_token_configured`).",
        "operationId": "getRustybinConfig",
        "responses": {
          "200": {
            "description": "Configuration",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "403": {
            "description": "permission_required: the caller lacks instance.read"
          }
        },
        "x-rustybin-permission": "instance.read"
      }
    },
    "/_rustybin/version": {
      "get": {
        "tags": [
          "Control Plane"
        ],
        "summary": "Version information",
        "operationId": "getRustybinVersion",
        "responses": {
          "200": {
            "description": "Version",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "name": {
                      "type": "string"
                    },
                    "version": {
                      "type": "string"
                    },
                    "git_sha": {
                      "type": [
                        "string",
                        "null"
                      ],
                      "description": "Commit the binary was built from, when known"
                    },
                    "rust_version": {
                      "type": "string"
                    },
                    "profile": {
                      "type": "string"
                    },
                    "control_auth": {
                      "type": "string",
                      "enum": [
                        "password",
                        "open",
                        "token",
                        "jwt"
                      ]
                    },
                    "hosted_mode": {
                      "type": "boolean"
                    },
                    "grpc_on_http": {
                      "type": "boolean"
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "permission_required: the caller lacks instance.read"
          }
        },
        "x-rustybin-permission": "instance.read"
      }
    },
    "/_rustybin/ready": {
      "get": {
        "tags": [
          "Control Plane"
        ],
        "summary": "Readiness probe",
        "description": "200 while the process serves HTTP, independent of the `/health` demo toggle. Exempt from control-plane auth, API keys, plan limits and inspector capture. With API keys (RUSTYBIN_SHARED_MODE, RUSTYBIN_REQUIRE_KEY) 503 until the key registry was loaded once.",
        "operationId": "getRustybinReady",
        "security": [],
        "responses": {
          "200": {
            "description": "Ready",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "status": {
                      "type": "string",
                      "enum": [
                        "ready"
                      ]
                    }
                  }
                }
              }
            }
          },
          "503": {
            "description": "Not ready: the key registry was never loaded",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "status": {
                      "type": "string",
                      "enum": [
                        "not_ready"
                      ]
                    },
                    "reason": {
                      "type": "string",
                      "enum": [
                        "rustybin_keys_unavailable"
                      ]
                    }
                  }
                }
              }
            }
          }
        },
        "x-rustybin-permission": "open"
      }
    },
    "/_rustybin/settings": {
      "get": {
        "tags": [
          "Control Plane"
        ],
        "summary": "Instance settings",
        "description": "Every registered setting with its value, where it comes from (`stored`, `env`, `default`) and whether RUSTYBIN_SETTINGS_LOCK holds it. Secrets are `{set, hint, source, unreadable}`. Admin.",
        "operationId": "getRustybinSettings",
        "responses": {
          "200": {
            "description": "Settings",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/RustybinSettings"
                }
              }
            }
          },
          "401": {
            "description": "Admin token required"
          },
          "403": {
            "description": "Disabled in public mode without an admin token"
          }
        },
        "x-rustybin-permission": "settings.read"
      },
      "patch": {
        "tags": [
          "Control Plane"
        ],
        "summary": "Change settings",
        "description": "Values are validated against each setting's schema; a `null` value forgets the stored one. A secret value is sealed at rest; `null` clears it. Admin. In password mode a change of console.user or console.password_hash also needs current_password (or the admin token itself), and signs every session out.",
        "operationId": "patchRustybinSettings",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "values": {
                    "type": "object",
                    "additionalProperties": {},
                    "description": "Non-secret settings by key"
                  },
                  "secrets": {
                    "type": "object",
                    "additionalProperties": {
                      "type": [
                        "string",
                        "null"
                      ]
                    },
                    "description": "Secret settings by key"
                  },
                  "current_password": {
                    "type": "string",
                    "description": "The console password: needed in password mode to change console.user or console.password_hash"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The new settings, with `changed` listing the keys that changed",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/RustybinSettings"
                }
              }
            }
          },
          "400": {
            "description": "Unknown keys or invalid values (`problems`)"
          },
          "401": {
            "description": "Admin token required"
          },
          "403": {
            "description": "The sign-in changes only with the current password (`reason`: current_password_required, invalid_credentials)"
          },
          "409": {
            "description": "Locked by RUSTYBIN_SETTINGS_LOCK (`locked`)"
          },
          "429": {
            "description": "Too many failed password checks (`reason`: rate_limited)"
          }
        },
        "x-rustybin-permission": "settings.write"
      }
    },
    "/_rustybin/settings/{key}": {
      "delete": {
        "tags": [
          "Control Plane"
        ],
        "summary": "Forget a stored setting",
        "description": "In password mode console.user and console.password_hash are reset here only with the admin token itself (the operator's recovery); anyone else sends PATCH with current_password.",
        "operationId": "deleteRustybinSetting",
        "parameters": [
          {
            "name": "key",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "example": "console.title"
          }
        ],
        "responses": {
          "200": {
            "description": "The settings after the reset",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/RustybinSettings"
                }
              }
            }
          },
          "400": {
            "description": "Invalid (`problems`), the sign-in without the admin token included"
          },
          "404": {
            "description": "No such setting"
          },
          "409": {
            "description": "Locked by RUSTYBIN_SETTINGS_LOCK"
          },
          "403": {
            "description": "permission_required: the caller lacks settings.write"
          }
        },
        "x-rustybin-permission": "settings.write"
      }
    },
    "/_rustybin/diagnostics": {
      "get": {
        "tags": [
          "Control Plane"
        ],
        "summary": "Instance diagnostics",
        "description": "Every check with its id, status (ok, warn, fail), message and fix (never a credential), and the worst status. Admin.",
        "operationId": "getRustybinDiagnostics",
        "responses": {
          "200": {
            "description": "The checks",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "401": {
            "description": "Admin token required"
          },
          "403": {
            "description": "permission_required: the caller lacks settings.read"
          }
        },
        "x-rustybin-permission": "settings.read"
      }
    },
    "/_rustybin/scenarios": {
      "get": {
        "tags": [
          "Control Plane"
        ],
        "summary": "Gateway scenarios and the caller's runs",
        "operationId": "listGatewayScenarios",
        "responses": {
          "200": {
            "description": "The catalogue and the runs",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "403": {
            "description": "permission_required: the caller lacks instance.read"
          }
        },
        "x-rustybin-permission": "instance.read"
      }
    },
    "/_rustybin/scenarios/{id}/runs": {
      "post": {
        "tags": [
          "Control Plane"
        ],
        "summary": "Start a scenario run (admin)",
        "description": "Creates the run's upstream (a mock that is never saved and ends with the run, or a /flaky route) and answers the gateway setup. At most 32 runs; a run lasts an hour.",
        "operationId": "startGatewayScenario",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "enum": [
                "retries",
                "rate_limiting",
                "credential_injection",
                "timeouts",
                "caching",
                "circuit_breaker",
                "request_size_limit",
                "cors",
                "header_transformation"
              ]
            }
          }
        ],
        "responses": {
          "201": {
            "description": "The run",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "404": {
            "description": "No such scenario"
          },
          "429": {
            "description": "Too many runs"
          },
          "403": {
            "description": "permission_required: the caller lacks scenarios.run"
          }
        },
        "x-rustybin-permission": "scenarios.run"
      }
    },
    "/_rustybin/scenarios/{id}/runs/{run}": {
      "get": {
        "tags": [
          "Control Plane"
        ],
        "summary": "A scenario run",
        "operationId": "getGatewayScenarioRun",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "enum": [
                "retries",
                "rate_limiting",
                "credential_injection",
                "timeouts",
                "caching",
                "circuit_breaker",
                "request_size_limit",
                "cors",
                "header_transformation"
              ]
            }
          },
          {
            "name": "run",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "The run with its setup and last verdict",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "404": {
            "description": "No such run in this session"
          },
          "403": {
            "description": "permission_required: the caller lacks instance.read"
          }
        },
        "x-rustybin-permission": "instance.read"
      },
      "delete": {
        "tags": [
          "Control Plane"
        ],
        "summary": "End a scenario run (admin)",
        "description": "Removes the run's mock and resets its flaky counters; nothing else.",
        "operationId": "endGatewayScenarioRun",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "enum": [
                "retries",
                "rate_limiting",
                "credential_injection",
                "timeouts",
                "caching",
                "circuit_breaker",
                "request_size_limit",
                "cors",
                "header_transformation"
              ]
            }
          },
          {
            "name": "run",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "What was removed",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "404": {
            "description": "No such run in this session"
          },
          "409": {
            "description": "A check is running"
          },
          "403": {
            "description": "permission_required: the caller lacks scenarios.run"
          }
        },
        "x-rustybin-permission": "scenarios.run"
      }
    },
    "/_rustybin/scenarios/{id}/runs/{run}/check": {
      "post": {
        "tags": [
          "Control Plane"
        ],
        "summary": "Check a scenario through the gateway (admin)",
        "description": "Sends the run's requests to gateway_url plus the scenario's path (through the egress policy, purpose scenario), then compares the answers with the upstream requests they caused.",
        "operationId": "checkGatewayScenario",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "enum": [
                "retries",
                "rate_limiting",
                "credential_injection",
                "timeouts",
                "caching",
                "circuit_breaker",
                "request_size_limit",
                "cors",
                "header_transformation"
              ]
            }
          },
          {
            "name": "run",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "gateway_url"
                ],
                "additionalProperties": false,
                "properties": {
                  "gateway_url": {
                    "type": "string",
                    "description": "The URL the gateway serves the route at"
                  },
                  "limit": {
                    "type": "integer",
                    "minimum": 1,
                    "maximum": 20,
                    "default": 5,
                    "description": "rate_limiting only: The limit set on the gateway: the check sends twice as many requests (1 to 20, default 5)"
                  },
                  "half_open_ms": {
                    "type": "integer",
                    "minimum": 100,
                    "maximum": 60000,
                    "default": 10000,
                    "description": "circuit_breaker only: How long the gateway keeps the circuit open before it lets a trial request through, in milliseconds: the check waits that long (100 to 60000, default 10000)"
                  },
                  "size_limit": {
                    "type": "integer",
                    "minimum": 16,
                    "maximum": 1048576,
                    "default": 1048576,
                    "description": "request_size_limit only: The request body limit set on the gateway, in bytes: the check sends a body half as large and one twice as large (16 to 1048576, default 1048576)"
                  },
                  "allowed_origin": {
                    "type": "string",
                    "format": "origin",
                    "maxLength": 200,
                    "default": "https://app.example.com",
                    "description": "cors only: An origin the gateway's CORS policy allows: the check sends a preflight and a GET from it (an origin scheme://host[:port], at most 200 characters, default https://app.example.com)"
                  },
                  "refused_origin": {
                    "type": "string",
                    "format": "origin",
                    "maxLength": 200,
                    "default": "https://elsewhere.example.net",
                    "description": "cors only: An origin the gateway's CORS policy does not allow: the check sends a preflight from it (an origin scheme://host[:port], at most 200 characters, default https://elsewhere.example.net)"
                  },
                  "upstream_cors": {
                    "type": "boolean",
                    "default": false,
                    "description": "cors only: Whether the gateway lets preflights through to the upstream, which answers CORS for allowed_origin (the run's upstream does so then), instead of answering them itself (true or false, default false)"
                  },
                  "add_request_header": {
                    "type": "string",
                    "format": "header-name",
                    "maxLength": 64,
                    "default": "X-Gateway-Added",
                    "description": "header_transformation only: A request header the gateway adds on the way to the upstream (a header name, at most 64 characters, default X-Gateway-Added)"
                  },
                  "add_request_value": {
                    "type": "string",
                    "maxLength": 200,
                    "description": "header_transformation only: The value the gateway gives add_request_header; any value passes when not given (optional, at most 200 visible characters)"
                  },
                  "remove_request_header": {
                    "type": "string",
                    "format": "header-name",
                    "maxLength": 64,
                    "default": "X-Client-Internal",
                    "description": "header_transformation only: A request header the gateway removes before the upstream: the check sends it (a header name, at most 64 characters, default X-Client-Internal)"
                  },
                  "add_response_header": {
                    "type": "string",
                    "format": "header-name",
                    "maxLength": 64,
                    "default": "X-Gateway-Response",
                    "description": "header_transformation only: A response header the gateway adds on the way back to the client (a header name, at most 64 characters, default X-Gateway-Response)"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The verdict",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "400": {
            "description": "Invalid body"
          },
          "403": {
            "description": "The egress policy refused the gateway URL"
          },
          "404": {
            "description": "No such run in this session"
          },
          "409": {
            "description": "A check is running"
          }
        },
        "x-rustybin-permission": "scenarios.run"
      }
    },
    "/_rustybin/tests": {
      "get": {
        "tags": [
          "Control Plane"
        ],
        "summary": "Saved tests",
        "operationId": "listSavedTests",
        "parameters": [
          {
            "name": "project",
            "in": "query",
            "required": false,
            "description": "One project's tests (instance: the instance's)",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "The tests with the variables each uses",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "403": {
            "description": "permission_required: the caller lacks tests.read"
          }
        },
        "x-rustybin-permission": "tests.read"
      },
      "post": {
        "tags": [
          "Control Plane"
        ],
        "summary": "Save a test (admin)",
        "description": "From a captured request (capture: its inspector id; secret-looking headers and query values become {{variables}}) or a written request, with assertions (default for a capture: its status). project: the project it belongs to (tests.write there). At most 200 tests, 64 KiB each.",
        "operationId": "saveTest",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "The saved test",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "400": {
            "description": "Invalid test"
          },
          "404": {
            "description": "No such capture you may read"
          },
          "409": {
            "description": "A test of that name exists"
          },
          "403": {
            "description": "permission_required: the caller lacks tests.write"
          }
        },
        "x-rustybin-permission": "tests.write"
      }
    },
    "/_rustybin/tests/{name}": {
      "get": {
        "tags": [
          "Control Plane"
        ],
        "summary": "A saved test",
        "operationId": "getSavedTest",
        "parameters": [
          {
            "name": "name",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "The test",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "404": {
            "description": "No such test"
          },
          "403": {
            "description": "permission_required: the caller lacks tests.read"
          }
        },
        "x-rustybin-permission": "tests.read"
      },
      "put": {
        "tags": [
          "Control Plane"
        ],
        "summary": "Save or replace a test (admin)",
        "operationId": "putSavedTest",
        "parameters": [
          {
            "name": "name",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The saved test",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "400": {
            "description": "Invalid test"
          },
          "403": {
            "description": "permission_required: the caller lacks tests.write"
          }
        },
        "x-rustybin-permission": "tests.write"
      },
      "delete": {
        "tags": [
          "Control Plane"
        ],
        "summary": "Delete a saved test (admin)",
        "operationId": "deleteSavedTest",
        "parameters": [
          {
            "name": "name",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Deleted",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "404": {
            "description": "No such test"
          },
          "403": {
            "description": "permission_required: the caller lacks tests.write"
          }
        },
        "x-rustybin-permission": "tests.write"
      }
    },
    "/_rustybin/tests/run": {
      "post": {
        "tags": [
          "Control Plane"
        ],
        "summary": "Run saved tests (admin)",
        "description": "Every test, or names; variables fill {{name}} references (else RUSTYBIN_TEST_* environment variables). Tests without a gateway run in process with the caller's session; gateway tests go through the egress policy (purpose replay). At most 200 requests and 60 seconds a run; one run at a time (409 while another goes). Every run is kept in the history: the answer has its run_id (the X-Rustybin-Test-Run header with JUnit) and the change since the previous run. X-Rustybin-Client (console or cli) labels the run's trigger, else api.",
        "operationId": "runSavedTests",
        "parameters": [
          {
            "name": "format",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "enum": [
                "json",
                "junit"
              ]
            }
          }
        ],
        "requestBody": {
          "required": false,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "additionalProperties": false,
                "properties": {
                  "names": {
                    "type": "array",
                    "items": {
                      "type": "string"
                    }
                  },
                  "variables": {
                    "type": "object",
                    "additionalProperties": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The report (JSON, or JUnit XML)",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              },
              "application/xml": {
                "schema": {
                  "type": "string"
                }
              }
            }
          },
          "403": {
            "description": "The egress policy refused a gateway"
          },
          "404": {
            "description": "No such test"
          },
          "409": {
            "description": "Another run is going"
          }
        },
        "x-rustybin-permission": "tests.run"
      }
    },
    "/_rustybin/tests/runs": {
      "get": {
        "tags": [
          "Control Plane"
        ],
        "summary": "The history of test runs (admin)",
        "description": "Every run of the saved tests (console, CLI, API, MCP), newest first: id, ran_at, trigger, principal (never a credential), the counts, the failing tests and the change since the previous run. At most 200 runs and 30 days (50 in memory without a state directory). Variables given to a run are never kept.",
        "operationId": "listTestRuns",
        "parameters": [
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 100,
              "default": 20
            }
          },
          {
            "name": "cursor",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "The next_cursor of the page before"
          }
        ],
        "responses": {
          "200": {
            "description": "A page: runs, next_cursor, total",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "403": {
            "description": "permission_required: the caller lacks tests.read"
          }
        },
        "x-rustybin-permission": "tests.read"
      },
      "delete": {
        "tags": [
          "Control Plane"
        ],
        "summary": "Forget every test run (admin)",
        "operationId": "clearTestRuns",
        "responses": {
          "200": {
            "description": "cleared: the number of runs forgotten",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "403": {
            "description": "permission_required: the caller lacks tests.write"
          }
        },
        "x-rustybin-permission": "tests.write"
      }
    },
    "/_rustybin/tests/runs/{id}": {
      "get": {
        "tags": [
          "Control Plane"
        ],
        "summary": "A kept test run (admin)",
        "operationId": "getTestRun",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "format",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "enum": [
                "json",
                "junit"
              ]
            }
          }
        ],
        "responses": {
          "200": {
            "description": "The run: the report, run_id, trigger, principal, selection, change (JSON, or JUnit XML)",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              },
              "application/xml": {
                "schema": {
                  "type": "string"
                }
              }
            }
          },
          "404": {
            "description": "No such run"
          },
          "403": {
            "description": "permission_required: the caller lacks tests.read"
          }
        },
        "x-rustybin-permission": "tests.read"
      }
    },
    "/_rustybin/tests/export": {
      "get": {
        "tags": [
          "Control Plane"
        ],
        "summary": "Saved tests as Hurl",
        "operationId": "exportSavedTests",
        "responses": {
          "200": {
            "description": "A Hurl file ({{base_url}} for in-process tests)",
            "content": {
              "text/plain": {
                "schema": {
                  "type": "string"
                }
              }
            }
          },
          "403": {
            "description": "permission_required: the caller lacks tests.read"
          }
        },
        "x-rustybin-permission": "tests.read"
      }
    },
    "/_rustybin/tests/schedules": {
      "get": {
        "tags": [
          "Control Plane"
        ],
        "summary": "Test schedules (admin)",
        "description": "Every schedule with its status: running, next_due, last_result (passed, failed or skipped), last_at, last_detail, last_run_id, last_passed, runs, skipped, last_notice (event, result: pending, retrying, delivered, failed, refused or dropped) and the recent outcomes.",
        "operationId": "listTestSchedules",
        "responses": {
          "200": {
            "description": "schedules, max_schedules, pending_notices",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "403": {
            "description": "permission_required: the caller lacks tests.read"
          }
        },
        "x-rustybin-permission": "tests.read"
      },
      "post": {
        "tags": [
          "Control Plane"
        ],
        "summary": "Create a test schedule (admin)",
        "description": "name, the tests (names, or prefix, or neither for every saved test), every (5m to 24h, aligned to multiples since the Unix epoch) or at (HH:MM, UTC), enabled, webhook (posted under the egress purpose notify, which has no default) and notify_recovery. At most 20 schedules. Variables come from RUSTYBIN_TEST_* only.",
        "operationId": "createTestSchedule",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "additionalProperties": false,
                "required": [
                  "name"
                ],
                "properties": {
                  "name": {
                    "type": "string",
                    "maxLength": 64,
                    "pattern": "^[A-Za-z0-9._-]+$"
                  },
                  "description": {
                    "type": "string",
                    "maxLength": 200
                  },
                  "names": {
                    "type": "array",
                    "items": {
                      "type": "string",
                      "maxLength": 64,
                      "pattern": "^[A-Za-z0-9._-]+$"
                    },
                    "maxItems": 200
                  },
                  "prefix": {
                    "type": "string",
                    "maxLength": 64,
                    "pattern": "^[A-Za-z0-9._-]+$"
                  },
                  "every": {
                    "type": "string",
                    "pattern": "^[0-9]+[smh]$",
                    "description": "5m to 24h"
                  },
                  "at": {
                    "type": "string",
                    "pattern": "^[0-2][0-9]:[0-5][0-9]$",
                    "description": "HH:MM, UTC"
                  },
                  "enabled": {
                    "type": "boolean",
                    "default": true
                  },
                  "webhook": {
                    "type": "string",
                    "format": "uri",
                    "description": "Posted a JSON summary when a run fails (egress purpose notify)"
                  },
                  "notify_recovery": {
                    "type": "boolean",
                    "default": false
                  }
                }
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "The schedule with its status",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "400": {
            "description": "Invalid schedule"
          },
          "409": {
            "description": "A schedule of that name exists"
          },
          "507": {
            "description": "20 schedules already"
          },
          "403": {
            "description": "permission_required: the caller lacks tests.write"
          }
        },
        "x-rustybin-permission": "tests.write"
      }
    },
    "/_rustybin/tests/schedules/{name}": {
      "get": {
        "tags": [
          "Control Plane"
        ],
        "summary": "A test schedule (admin)",
        "operationId": "getTestSchedule",
        "parameters": [
          {
            "name": "name",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "The schedule with its status",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "404": {
            "description": "No such schedule"
          },
          "403": {
            "description": "permission_required: the caller lacks tests.read"
          }
        },
        "x-rustybin-permission": "tests.read"
      },
      "put": {
        "tags": [
          "Control Plane"
        ],
        "summary": "Save or replace a test schedule (admin)",
        "operationId": "putTestSchedule",
        "description": "The whole schedule (the name comes from the path); a replaced schedule keeps its status.",
        "parameters": [
          {
            "name": "name",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The schedule with its status",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "400": {
            "description": "Invalid schedule"
          },
          "507": {
            "description": "20 schedules already"
          },
          "403": {
            "description": "permission_required: the caller lacks tests.write"
          }
        },
        "x-rustybin-permission": "tests.write"
      },
      "delete": {
        "tags": [
          "Control Plane"
        ],
        "summary": "Delete a test schedule (admin)",
        "operationId": "deleteTestSchedule",
        "parameters": [
          {
            "name": "name",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Deleted",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "404": {
            "description": "No such schedule"
          },
          "403": {
            "description": "permission_required: the caller lacks tests.write"
          }
        },
        "x-rustybin-permission": "tests.write"
      }
    },
    "/_rustybin/tests/schedules/{name}/run": {
      "post": {
        "tags": [
          "Control Plane"
        ],
        "summary": "Run a test schedule now (admin)",
        "description": "Runs the schedule's tests as the scheduler would (trigger schedule:<name>, kept in the history, the notice queued when it fails); its next time stays. 409 while another run of the saved tests goes or the harness sends load.",
        "operationId": "runTestSchedule",
        "parameters": [
          {
            "name": "name",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "result (passed, failed or skipped), detail, run (the kept run, as POST /_rustybin/tests/run answers it), schedule (with its status)",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "404": {
            "description": "No such schedule"
          },
          "409": {
            "description": "Another run goes, or the harness sends load"
          },
          "403": {
            "description": "permission_required: the caller lacks tests.run"
          }
        },
        "x-rustybin-permission": "tests.run"
      }
    },
    "/_rustybin/checkpoints": {
      "get": {
        "tags": [
          "Control Plane"
        ],
        "summary": "Checkpoints",
        "operationId": "listCheckpoints",
        "description": "This instance's checkpoints; from=git lists the configuration repository's instead (the files under <git.path>/checkpoints/ at the working copy's HEAD, after a pull; admin), each read within the 16 MiB cap and checked, or listed with the reason it cannot be restored.",
        "parameters": [
          {
            "name": "from",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "enum": [
                "instance",
                "git"
              ],
              "default": "instance"
            }
          },
          {
            "name": "project",
            "in": "query",
            "required": false,
            "description": "One project's checkpoints (instance: the instance's)",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "The checkpoints and their scope",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "409": {
            "description": "from=git: source control is not configured or connected"
          },
          "403": {
            "description": "permission_required: the caller lacks mocks.read"
          }
        },
        "x-rustybin-permission": "mocks.read"
      },
      "post": {
        "tags": [
          "Control Plane"
        ],
        "summary": "Save a checkpoint (admin)",
        "operationId": "saveCheckpoint",
        "description": "Saves the instance's API mocks (deployed revision, a draft that differs, on or off, stateful data) and the health toggle. Never visitors' or keys' mocks, file mocks, settings or secrets. At most 20.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "name"
                ],
                "additionalProperties": false,
                "properties": {
                  "name": {
                    "type": "string"
                  },
                  "replace": {
                    "type": "boolean"
                  },
                  "project": {
                    "type": "string",
                    "description": "Keep this project's mocks only (a restore changes only those, never the health toggle); absent: the instance's API mocks, or the one project the caller works in"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Saved",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "409": {
            "description": "A checkpoint of that name exists"
          },
          "403": {
            "description": "permission_required: the caller lacks checkpoints.write"
          }
        },
        "x-rustybin-permission": "checkpoints.write"
      }
    },
    "/_rustybin/checkpoints/{name}": {
      "get": {
        "tags": [
          "Control Plane"
        ],
        "summary": "A checkpoint",
        "operationId": "getCheckpoint",
        "parameters": [
          {
            "name": "name",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "What it holds",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "404": {
            "description": "No such checkpoint"
          },
          "403": {
            "description": "permission_required: the caller lacks mocks.read"
          }
        },
        "x-rustybin-permission": "mocks.read"
      },
      "delete": {
        "tags": [
          "Control Plane"
        ],
        "summary": "Delete a checkpoint (admin)",
        "operationId": "deleteCheckpoint",
        "parameters": [
          {
            "name": "name",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Deleted",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "404": {
            "description": "No such checkpoint"
          },
          "403": {
            "description": "permission_required: the caller lacks checkpoints.write"
          }
        },
        "x-rustybin-permission": "checkpoints.write"
      }
    },
    "/_rustybin/checkpoints/{name}/restore": {
      "post": {
        "tags": [
          "Control Plane"
        ],
        "summary": "Restore a checkpoint (admin)",
        "operationId": "restoreCheckpoint",
        "description": "Brings the instance's API mocks back as saved (created, replaced, data restored, unchanged; mocks the checkpoint does not hold deleted), sets the health toggle and resets the flaky counters. dry_run answers the same without changing anything. from=git restores the configuration repository's checkpoint of that name (at the working copy's HEAD): untrusted input, read within the size cap, checked and compiled like a local one.",
        "parameters": [
          {
            "name": "name",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "dry_run",
            "in": "query",
            "required": false,
            "schema": {
              "type": "boolean"
            }
          },
          {
            "name": "from",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "enum": [
                "instance",
                "git"
              ],
              "default": "instance"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "What changed",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "404": {
            "description": "No such checkpoint"
          },
          "413": {
            "description": "from=git: the file is larger than a checkpoint may be"
          },
          "422": {
            "description": "from=git: the file is not a valid checkpoint"
          },
          "403": {
            "description": "permission_required: the caller lacks checkpoints.restore"
          }
        },
        "x-rustybin-permission": "checkpoints.restore"
      }
    },
    "/_rustybin/egress/check": {
      "get": {
        "tags": [
          "Control Plane"
        ],
        "summary": "Dry check of a URL against the outbound policy",
        "description": "What the policy would say to `url` for `purpose`, without calling it. The addresses a name resolves to are checked again when a call is made.",
        "operationId": "checkRustybinEgress",
        "parameters": [
          {
            "name": "url",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "purpose",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "default": "mcp_relay"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "The answer",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "url": {
                      "type": "string"
                    },
                    "origin": {
                      "type": "string"
                    },
                    "purpose": {
                      "type": "string"
                    },
                    "allowed": {
                      "type": "boolean"
                    },
                    "reasons": {
                      "type": "array",
                      "items": {
                        "type": "string"
                      }
                    },
                    "rule": {
                      "type": "object"
                    },
                    "note": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "No url, or an unknown purpose"
          },
          "401": {
            "description": "Admin token required"
          },
          "403": {
            "description": "permission_required: the caller lacks settings.read"
          }
        },
        "x-rustybin-permission": "settings.read"
      }
    },
    "/_rustybin/egress": {
      "get": {
        "tags": [
          "Control Plane"
        ],
        "summary": "Outbound connection policy",
        "description": "The allowlist as the instance sees it, where it comes from, each feature's own rule, and the last 100 decisions (newest first). Admin.",
        "operationId": "getRustybinEgress",
        "responses": {
          "200": {
            "description": "Policy",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "allow": {
                      "type": "array",
                      "items": {
                        "type": "string"
                      }
                    },
                    "allow_source": {
                      "type": "string",
                      "enum": [
                        "stored",
                        "env",
                        "default"
                      ]
                    },
                    "allow_loopback": {
                      "type": "boolean"
                    },
                    "allow_loopback_source": {
                      "type": "string",
                      "enum": [
                        "stored",
                        "env",
                        "default"
                      ]
                    },
                    "public_mode": {
                      "type": "boolean"
                    },
                    "warnings": {
                      "type": "array",
                      "items": {
                        "type": "string"
                      }
                    },
                    "always_refused": {
                      "type": "array",
                      "items": {
                        "type": "string"
                      }
                    },
                    "purposes": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "purpose": {
                            "type": "string"
                          },
                          "title": {
                            "type": "string"
                          },
                          "configured_by": {
                            "type": "string"
                          },
                          "allow": {
                            "type": "array",
                            "items": {
                              "type": "string"
                            }
                          },
                          "any": {
                            "type": "boolean"
                          },
                          "loopback": {
                            "type": "boolean"
                          }
                        }
                      }
                    },
                    "decisions": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "at": {
                            "type": "string",
                            "format": "date-time"
                          },
                          "purpose": {
                            "type": "string"
                          },
                          "origin": {
                            "type": "string"
                          },
                          "addrs": {
                            "type": "array",
                            "items": {
                              "type": "string"
                            }
                          },
                          "allowed": {
                            "type": "boolean"
                          },
                          "reason": {
                            "type": "string"
                          }
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Admin token required"
          },
          "403": {
            "description": "permission_required: the caller lacks settings.read"
          }
        },
        "x-rustybin-permission": "settings.read"
      }
    },
    "/_rustybin/harness": {
      "get": {
        "tags": [
          "Harness"
        ],
        "summary": "Harness node status",
        "description": "Roles, caps, engine, allowlist, the active run. `enabled: false` when harness mode is off.",
        "operationId": "getHarnessStatus",
        "responses": {
          "200": {
            "description": "Status",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "403": {
            "description": "permission_required: the caller lacks harness.read"
          }
        },
        "x-rustybin-permission": "harness.read"
      }
    },
    "/_rustybin/harness/schema": {
      "get": {
        "tags": [
          "Harness"
        ],
        "summary": "Scenario JSON Schema",
        "description": "JSON Schema (draft 2020-12) of a scenario, with this node's caps as bounds (`x-caps`).",
        "operationId": "getHarnessSchema",
        "responses": {
          "200": {
            "description": "Schema",
            "content": {
              "application/schema+json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "403": {
            "description": "permission_required: the caller lacks harness.read"
          }
        },
        "x-rustybin-permission": "harness.read"
      }
    },
    "/_rustybin/harness/scenarios": {
      "get": {
        "tags": [
          "Harness"
        ],
        "summary": "Built-in scenarios",
        "operationId": "listHarnessScenarios",
        "responses": {
          "200": {
            "description": "Scenarios with their summaries",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "403": {
            "description": "permission_required: the caller lacks harness.read"
          }
        },
        "x-rustybin-permission": "harness.read"
      }
    },
    "/_rustybin/harness/scenarios/{name}": {
      "get": {
        "tags": [
          "Harness"
        ],
        "summary": "One built-in scenario",
        "operationId": "getHarnessScenario",
        "parameters": [
          {
            "name": "name",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "format",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "enum": [
                "json",
                "yaml"
              ]
            }
          }
        ],
        "responses": {
          "200": {
            "description": "The scenario",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HarnessScenario"
                }
              },
              "application/yaml": {
                "schema": {
                  "type": "string"
                }
              }
            }
          },
          "404": {
            "description": "Unknown scenario"
          },
          "403": {
            "description": "permission_required: the caller lacks harness.read"
          }
        },
        "x-rustybin-permission": "harness.read"
      },
      "put": {
        "tags": [
          "Harness"
        ],
        "summary": "Save a scenario",
        "description": "Validated against this node's caps and kept under the name (at most 100; RUSTYBIN_HARNESS_STATE_DIR writes them to disk). Built-in names are taken.",
        "operationId": "saveHarnessScenario",
        "parameters": [
          {
            "name": "name",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/HarnessScenario"
              }
            },
            "application/yaml": {
              "schema": {
                "type": "string"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Saved",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "200": {
            "description": "Replaced",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "400": {
            "description": "Invalid scenario or name"
          },
          "409": {
            "description": "A built-in name"
          },
          "404": {
            "description": "Harness mode is off (RUSTYBIN_HARNESS=on), or no such run"
          },
          "403": {
            "description": "permission_required: the caller lacks harness.run"
          }
        },
        "x-rustybin-permission": "harness.run"
      },
      "delete": {
        "tags": [
          "Harness"
        ],
        "summary": "Delete a saved scenario",
        "operationId": "deleteHarnessScenario",
        "parameters": [
          {
            "name": "name",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "204": {
            "description": "Deleted"
          },
          "409": {
            "description": "A built-in scenario"
          },
          "404": {
            "description": "Harness mode is off (RUSTYBIN_HARNESS=on), or no such run"
          },
          "403": {
            "description": "permission_required: the caller lacks harness.run"
          }
        },
        "x-rustybin-permission": "harness.run"
      }
    },
    "/_rustybin/harness/validate": {
      "post": {
        "tags": [
          "Harness"
        ],
        "summary": "Validate a scenario",
        "description": "Parses and validates a scenario against this node's caps and returns every problem, the normalised scenario, its hash and summary. Sends nothing.",
        "operationId": "validateHarnessScenario",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/HarnessScenario"
              }
            },
            "application/yaml": {
              "schema": {
                "type": "string"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Validation result (`valid`, `problems`, `scenario`, `summary`)",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "400": {
            "description": "Unparseable scenario"
          },
          "403": {
            "description": "permission_required: the caller lacks harness.read"
          }
        },
        "x-rustybin-permission": "harness.read"
      }
    },
    "/_rustybin/harness/runs": {
      "get": {
        "tags": [
          "Harness"
        ],
        "summary": "Runs on this node",
        "operationId": "listHarnessRuns",
        "responses": {
          "200": {
            "description": "Runs",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "404": {
            "description": "Harness mode is off (RUSTYBIN_HARNESS=on), or no such run"
          },
          "403": {
            "description": "permission_required: the caller lacks harness.read"
          }
        },
        "x-rustybin-permission": "harness.read"
      },
      "post": {
        "tags": [
          "Harness"
        ],
        "summary": "Start a run",
        "description": "Validates the scenario, pins and (optionally) verifies its targets and starts the run. One run at a time per node (409). Targets outside RUSTYBIN_HARNESS_TARGETS are refused (403).",
        "operationId": "createHarnessRun",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/HarnessScenario"
              }
            },
            "application/yaml": {
              "schema": {
                "type": "string"
              }
            }
          }
        },
        "responses": {
          "202": {
            "description": "The run (live view), with a Location header",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "400": {
            "description": "Invalid scenario (`problems`)"
          },
          "403": {
            "description": "No client role, a target not allowed, or verification failed"
          },
          "409": {
            "description": "A run is active"
          },
          "404": {
            "description": "Harness mode is off (RUSTYBIN_HARNESS=on), or no such run"
          }
        },
        "x-rustybin-permission": "harness.run"
      }
    },
    "/_rustybin/harness/runs/{run}": {
      "get": {
        "tags": [
          "Harness"
        ],
        "summary": "Live stats of a run",
        "operationId": "getHarnessRun",
        "parameters": [
          {
            "name": "run",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Live view",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "404": {
            "description": "Harness mode is off (RUSTYBIN_HARNESS=on), or no such run"
          },
          "403": {
            "description": "permission_required: the caller lacks harness.read"
          }
        },
        "x-rustybin-permission": "harness.read"
      },
      "patch": {
        "tags": [
          "Harness"
        ],
        "summary": "Change a running run",
        "description": "Checked like a new scenario (the caps included), applied on the next scheduler pass, recorded in the run's log and report.",
        "operationId": "changeHarnessRun",
        "parameters": [
          {
            "name": "run",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "description": "A live change: rate_multiplier, pause, resume, hold, skip_stage, set, add_layer, remove_layer, and layer to aim one (the schema is $defs.change of GET /_rustybin/harness/schema)."
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The run's controls after the change",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "400": {
            "description": "Refused (`problems`)"
          },
          "409": {
            "description": "Finished, or a cluster run (change it on the leader)"
          },
          "404": {
            "description": "Harness mode is off (RUSTYBIN_HARNESS=on), or no such run"
          },
          "403": {
            "description": "permission_required: the caller lacks harness.run"
          }
        },
        "x-rustybin-permission": "harness.run"
      }
    },
    "/_rustybin/harness/runs/{run}/stop": {
      "post": {
        "tags": [
          "Harness"
        ],
        "summary": "Stop a run",
        "operationId": "stopHarnessRun",
        "parameters": [
          {
            "name": "run",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "202": {
            "description": "Stopping (drains, then reports)"
          },
          "200": {
            "description": "Already finished"
          },
          "404": {
            "description": "Harness mode is off (RUSTYBIN_HARNESS=on), or no such run"
          },
          "403": {
            "description": "permission_required: the caller lacks harness.run"
          }
        },
        "x-rustybin-permission": "harness.run"
      }
    },
    "/_rustybin/harness/runs/{run}/report": {
      "get": {
        "tags": [
          "Harness"
        ],
        "summary": "Final report",
        "operationId": "getHarnessReport",
        "parameters": [
          {
            "name": "run",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "format",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "enum": [
                "json",
                "text",
                "junit"
              ]
            }
          }
        ],
        "responses": {
          "200": {
            "description": "The report",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              },
              "text/plain": {
                "schema": {
                  "type": "string"
                }
              },
              "application/xml": {
                "schema": {
                  "type": "string"
                }
              }
            }
          },
          "409": {
            "description": "The run has not finished"
          },
          "404": {
            "description": "Harness mode is off (RUSTYBIN_HARNESS=on), or no such run"
          },
          "403": {
            "description": "permission_required: the caller lacks harness.read"
          }
        },
        "x-rustybin-permission": "harness.read"
      }
    },
    "/_rustybin/harness/stop": {
      "post": {
        "tags": [
          "Harness"
        ],
        "summary": "Kill switch",
        "description": "Stops every run on this node now.",
        "operationId": "harnessKillSwitch",
        "responses": {
          "200": {
            "description": "Stopped runs",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "404": {
            "description": "Harness mode is off (RUSTYBIN_HARNESS=on), or no such run"
          },
          "403": {
            "description": "permission_required: the caller lacks harness.run"
          }
        },
        "x-rustybin-permission": "harness.run"
      }
    },
    "/harness": {
      "get": {
        "tags": [
          "Harness"
        ],
        "summary": "Shaped upstream",
        "description": "Answers with the run's server profile (scenario `servers`: log-normal latency, status mix, padded JSON body, chunked streaming, first-byte delay) when the request carries a verified harness marker, else 200 with a 256 byte body.",
        "operationId": "getShapedRootGET",
        "responses": {
          "200": {
            "description": "The shaped answer (any configured status)",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          }
        }
      },
      "post": {
        "tags": [
          "Harness"
        ],
        "summary": "Shaped upstream",
        "description": "Answers with the run's server profile (scenario `servers`: log-normal latency, status mix, padded JSON body, chunked streaming, first-byte delay) when the request carries a verified harness marker, else 200 with a 256 byte body.",
        "operationId": "getShapedRootPOST",
        "responses": {
          "200": {
            "description": "The shaped answer (any configured status)",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          }
        }
      },
      "put": {
        "tags": [
          "Harness"
        ],
        "summary": "Shaped upstream",
        "description": "Answers with the run's server profile (scenario `servers`: log-normal latency, status mix, padded JSON body, chunked streaming, first-byte delay) when the request carries a verified harness marker, else 200 with a 256 byte body.",
        "operationId": "getShapedRootPUT",
        "responses": {
          "200": {
            "description": "The shaped answer (any configured status)",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          }
        }
      },
      "patch": {
        "tags": [
          "Harness"
        ],
        "summary": "Shaped upstream",
        "description": "Answers with the run's server profile (scenario `servers`: log-normal latency, status mix, padded JSON body, chunked streaming, first-byte delay) when the request carries a verified harness marker, else 200 with a 256 byte body.",
        "operationId": "getShapedRootPATCH",
        "responses": {
          "200": {
            "description": "The shaped answer (any configured status)",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          }
        }
      },
      "delete": {
        "tags": [
          "Harness"
        ],
        "summary": "Shaped upstream",
        "description": "Answers with the run's server profile (scenario `servers`: log-normal latency, status mix, padded JSON body, chunked streaming, first-byte delay) when the request carries a verified harness marker, else 200 with a 256 byte body.",
        "operationId": "getShapedRootDELETE",
        "responses": {
          "200": {
            "description": "The shaped answer (any configured status)",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          }
        }
      }
    },
    "/harness/{path}": {
      "get": {
        "tags": [
          "Harness"
        ],
        "summary": "Shaped upstream",
        "description": "Answers with the run's server profile (scenario `servers`: log-normal latency, status mix, padded JSON body, chunked streaming, first-byte delay) when the request carries a verified harness marker, else 200 with a 256 byte body.",
        "operationId": "getShapedPathGET",
        "responses": {
          "200": {
            "description": "The shaped answer (any configured status)",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          }
        },
        "parameters": [
          {
            "name": "path",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ]
      },
      "post": {
        "tags": [
          "Harness"
        ],
        "summary": "Shaped upstream",
        "description": "Answers with the run's server profile (scenario `servers`: log-normal latency, status mix, padded JSON body, chunked streaming, first-byte delay) when the request carries a verified harness marker, else 200 with a 256 byte body.",
        "operationId": "getShapedPathPOST",
        "responses": {
          "200": {
            "description": "The shaped answer (any configured status)",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          }
        },
        "parameters": [
          {
            "name": "path",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ]
      },
      "put": {
        "tags": [
          "Harness"
        ],
        "summary": "Shaped upstream",
        "description": "Answers with the run's server profile (scenario `servers`: log-normal latency, status mix, padded JSON body, chunked streaming, first-byte delay) when the request carries a verified harness marker, else 200 with a 256 byte body.",
        "operationId": "getShapedPathPUT",
        "responses": {
          "200": {
            "description": "The shaped answer (any configured status)",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          }
        },
        "parameters": [
          {
            "name": "path",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ]
      },
      "patch": {
        "tags": [
          "Harness"
        ],
        "summary": "Shaped upstream",
        "description": "Answers with the run's server profile (scenario `servers`: log-normal latency, status mix, padded JSON body, chunked streaming, first-byte delay) when the request carries a verified harness marker, else 200 with a 256 byte body.",
        "operationId": "getShapedPathPATCH",
        "responses": {
          "200": {
            "description": "The shaped answer (any configured status)",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          }
        },
        "parameters": [
          {
            "name": "path",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ]
      },
      "delete": {
        "tags": [
          "Harness"
        ],
        "summary": "Shaped upstream",
        "description": "Answers with the run's server profile (scenario `servers`: log-normal latency, status mix, padded JSON body, chunked streaming, first-byte delay) when the request carries a verified harness marker, else 200 with a 256 byte body.",
        "operationId": "getShapedPathDELETE",
        "responses": {
          "200": {
            "description": "The shaped answer (any configured status)",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          }
        },
        "parameters": [
          {
            "name": "path",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ]
      }
    },
    "/.well-known/rustybin-harness": {
      "get": {
        "tags": [
          "Harness"
        ],
        "summary": "Harness verification token",
        "operationId": "getHarnessVerificationToken",
        "security": [],
        "responses": {
          "200": {
            "description": "The token",
            "content": {
              "text/plain": {
                "schema": {
                  "type": "string"
                }
              }
            }
          },
          "404": {
            "description": "Harness mode is off (RUSTYBIN_HARNESS=on), or no such run"
          }
        }
      }
    },
    "/_rustybin/harness/join": {
      "post": {
        "tags": [
          "Harness"
        ],
        "summary": "Join a cluster",
        "description": "Tells this node to join the cluster at `url` with `join_token` (orchestrated). The URL must not resolve to a forbidden address.",
        "operationId": "joinHarnessCluster",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "url",
                  "join_token"
                ],
                "properties": {
                  "url": {
                    "type": "string"
                  },
                  "join_token": {
                    "type": "string"
                  },
                  "advertise": {
                    "type": "string"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Joined",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "400": {
            "description": "Invalid body or URL"
          },
          "403": {
            "description": "Forbidden join address"
          },
          "409": {
            "description": "Already a member, or the leader refused"
          },
          "404": {
            "description": "Harness mode is off (RUSTYBIN_HARNESS=on), or no such run"
          }
        },
        "x-rustybin-permission": "harness.cluster"
      }
    },
    "/_rustybin/harness/leave": {
      "post": {
        "tags": [
          "Harness"
        ],
        "summary": "Leave the cluster",
        "operationId": "leaveHarnessCluster",
        "responses": {
          "200": {
            "description": "Left",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "404": {
            "description": "Harness mode is off (RUSTYBIN_HARNESS=on), or no such run"
          },
          "403": {
            "description": "permission_required: the caller lacks harness.cluster"
          }
        },
        "x-rustybin-permission": "harness.cluster"
      }
    },
    "/_rustybin/harness/clusters": {
      "get": {
        "tags": [
          "Harness"
        ],
        "summary": "Clusters this node leads",
        "operationId": "listHarnessClusters",
        "responses": {
          "200": {
            "description": "Clusters",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "404": {
            "description": "Harness mode is off (RUSTYBIN_HARNESS=on), or no such run"
          },
          "403": {
            "description": "permission_required: the caller lacks harness.read"
          }
        },
        "x-rustybin-permission": "harness.read"
      },
      "post": {
        "tags": [
          "Harness"
        ],
        "summary": "Create a cluster",
        "description": "Needs the coordinator role. Returns the cluster and its join token (once).",
        "operationId": "createHarnessCluster",
        "requestBody": {
          "required": false,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "cluster_id": {
                    "type": "string"
                  },
                  "min_nodes": {
                    "type": "object",
                    "properties": {
                      "client": {
                        "type": "integer"
                      },
                      "server": {
                        "type": "integer"
                      }
                    }
                  },
                  "lease": {
                    "type": "string",
                    "description": "500ms to 60s, default 5s"
                  },
                  "election_timeout": {
                    "type": "string",
                    "description": "How long without the leader before an election starts: 200ms, below the lease (default RUSTYBIN_HARNESS_ELECTION_TIMEOUT, 3s)"
                  },
                  "join_token": {
                    "type": "string",
                    "description": "At least 16 characters; random when absent"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "The cluster and its join token",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "400": {
            "description": "Invalid body"
          },
          "403": {
            "description": "No coordinator role"
          },
          "409": {
            "description": "The id exists, or too many clusters"
          },
          "404": {
            "description": "Harness mode is off (RUSTYBIN_HARNESS=on), or no such run"
          }
        },
        "x-rustybin-permission": "harness.cluster"
      }
    },
    "/_rustybin/harness/clusters/{id}": {
      "get": {
        "tags": [
          "Harness"
        ],
        "summary": "A cluster",
        "operationId": "getHarnessCluster",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Members, health, clock offsets, the current run",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "307": {
            "description": "This node is a member; the leader answers"
          },
          "404": {
            "description": "Harness mode is off (RUSTYBIN_HARNESS=on), or no such run"
          },
          "403": {
            "description": "permission_required: the caller lacks harness.read"
          }
        },
        "x-rustybin-permission": "harness.read"
      },
      "delete": {
        "tags": [
          "Harness"
        ],
        "summary": "Delete a cluster",
        "operationId": "deleteHarnessCluster",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "204": {
            "description": "Deleted"
          },
          "409": {
            "description": "A run is active"
          },
          "404": {
            "description": "Harness mode is off (RUSTYBIN_HARNESS=on), or no such run"
          },
          "403": {
            "description": "permission_required: the caller lacks harness.cluster"
          }
        },
        "x-rustybin-permission": "harness.cluster"
      }
    },
    "/_rustybin/harness/clusters/{id}/upstreams": {
      "get": {
        "tags": [
          "Harness"
        ],
        "summary": "Server nodes' URLs",
        "operationId": "getHarnessUpstreams",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Advertised URLs",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "type": "string"
                  }
                }
              }
            }
          },
          "307": {
            "description": "This node is a member; the leader answers"
          },
          "404": {
            "description": "Harness mode is off (RUSTYBIN_HARNESS=on), or no such run"
          },
          "403": {
            "description": "permission_required: the caller lacks harness.read"
          }
        },
        "x-rustybin-permission": "harness.read"
      }
    },
    "/_rustybin/harness/clusters/{id}/leader/step-aside": {
      "post": {
        "tags": [
          "Harness"
        ],
        "summary": "Hand the cluster to the first in line",
        "description": "Before maintenance: the leader stops renewing leases and the first in the succession takes over by the ordinary election, with the run still on. 409 with fewer than three eligible nodes, or on a member (it names the leader).",
        "operationId": "stepAsideHarnessLeader",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "202": {
            "description": "Who is expected to take over",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "404": {
            "description": "Harness mode is off (RUSTYBIN_HARNESS=on), or no such run"
          },
          "409": {
            "description": "Nobody can take over, or this node does not lead"
          },
          "403": {
            "description": "permission_required: the caller lacks harness.cluster"
          }
        },
        "x-rustybin-permission": "harness.cluster"
      }
    },
    "/_rustybin/harness/clusters/{id}/leader": {
      "get": {
        "tags": [
          "Harness"
        ],
        "summary": "The cluster's leader",
        "description": "The leader (node, control URL, term, since), the eligible nodes, whether failover is available (three or more), the succession with work scores and the history of leader changes. Every member answers; never redirected.",
        "operationId": "getHarnessLeader",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "The leader as this node sees it",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "404": {
            "description": "Harness mode is off (RUSTYBIN_HARNESS=on), or no such run"
          },
          "403": {
            "description": "permission_required: the caller lacks harness.read"
          }
        },
        "x-rustybin-permission": "harness.read"
      }
    },
    "/_rustybin/harness/clusters/{id}/election/vote": {
      "post": {
        "tags": [
          "Harness"
        ],
        "summary": "Node vote",
        "description": "A candidate asks an eligible node for its vote: `{term, candidate, snapshot}` with the candidate's node credential as bearer. Granted when the node lost the leader too, has not voted in the term and the candidate's snapshot is at least as recent.",
        "operationId": "harnessNodeVote",
        "security": [],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "`{granted, term, leader?, reason}`",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "401": {
            "description": "Invalid node credential"
          },
          "403": {
            "description": "This node is not eligible"
          },
          "404": {
            "description": "Harness mode is off (RUSTYBIN_HARNESS=on), or no such run"
          }
        },
        "x-rustybin-permission": "open"
      }
    },
    "/_rustybin/harness/clusters/{id}/election/elected": {
      "post": {
        "tags": [
          "Harness"
        ],
        "summary": "New leader announcement",
        "description": "A new leader announces its term (its node credential as bearer). A node that led an older term steps down; a member follows the new leader.",
        "operationId": "harnessNodeElected",
        "security": [],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "`{accepted}`",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "401": {
            "description": "Invalid node credential"
          },
          "404": {
            "description": "Harness mode is off (RUSTYBIN_HARNESS=on), or no such run"
          }
        },
        "x-rustybin-permission": "open"
      }
    },
    "/_rustybin/harness/clusters/{id}/nodes": {
      "post": {
        "tags": [
          "Harness"
        ],
        "summary": "Node join",
        "description": "Called by nodes with the join token as bearer. Returns a node credential and a lease.",
        "operationId": "harnessNodeJoin",
        "security": [],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Credential, lease, leader, clock stamps",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "401": {
            "description": "Invalid join token"
          },
          "404": {
            "description": "Harness mode is off (RUSTYBIN_HARNESS=on), or no such run"
          }
        },
        "x-rustybin-permission": "open"
      }
    },
    "/_rustybin/harness/clusters/{id}/nodes/{node}/heartbeat": {
      "post": {
        "tags": [
          "Harness"
        ],
        "summary": "Node heartbeat",
        "description": "Called by nodes with their node credential as bearer: a long poll (up to 10 s, at most a third of the election timeout) carrying cumulative stats, the term and a work report; returns assignments, shares, stops, the lease and the snapshot when it changed. A node that does not lead answers 409 naming the leader it knows; a leader without a majority of the eligible nodes answers 503 (no lease renewal).",
        "operationId": "harnessNodeHeartbeat",
        "security": [],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "node",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Assignments and the lease",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "401": {
            "description": "Invalid node credential"
          },
          "404": {
            "description": "Harness mode is off (RUSTYBIN_HARNESS=on), or no such run"
          }
        },
        "x-rustybin-permission": "open"
      }
    },
    "/_rustybin/harness/clusters/{id}/runs": {
      "get": {
        "tags": [
          "Harness"
        ],
        "summary": "Cluster runs",
        "operationId": "listHarnessClusterRuns",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Runs",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "307": {
            "description": "This node is a member; the leader answers"
          },
          "404": {
            "description": "Harness mode is off (RUSTYBIN_HARNESS=on), or no such run"
          },
          "403": {
            "description": "permission_required: the caller lacks harness.read"
          }
        },
        "x-rustybin-permission": "harness.read"
      },
      "post": {
        "tags": [
          "Harness"
        ],
        "summary": "Submit a scenario",
        "description": "Validated against the cluster (each client's share against the caps), not started.",
        "operationId": "createHarnessClusterRun",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/HarnessScenario"
              }
            },
            "application/yaml": {
              "schema": {
                "type": "string"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "The run and its quorum",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "400": {
            "description": "Invalid scenario (`problems`)"
          },
          "307": {
            "description": "This node is a member; the leader answers"
          },
          "404": {
            "description": "Harness mode is off (RUSTYBIN_HARNESS=on), or no such run"
          },
          "403": {
            "description": "permission_required: the caller lacks harness.run"
          }
        },
        "x-rustybin-permission": "harness.run"
      }
    },
    "/_rustybin/harness/clusters/{id}/runs/{run}": {
      "get": {
        "tags": [
          "Harness"
        ],
        "summary": "Live merged stats of a cluster run",
        "operationId": "getHarnessClusterRun",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "run",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Live view",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "307": {
            "description": "This node is a member; the leader answers"
          },
          "404": {
            "description": "Harness mode is off (RUSTYBIN_HARNESS=on), or no such run"
          },
          "403": {
            "description": "permission_required: the caller lacks harness.read"
          }
        },
        "x-rustybin-permission": "harness.read"
      },
      "patch": {
        "tags": [
          "Harness"
        ],
        "summary": "Change a running cluster run",
        "description": "Checked against every client node's capacity for its share, carried in the cluster snapshot, followed by the nodes on their next heartbeat.",
        "operationId": "changeHarnessClusterRun",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "run",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "description": "A live change: rate_multiplier, pause, resume, hold, skip_stage, set, add_layer, remove_layer, and layer to aim one (the schema is $defs.change of GET /_rustybin/harness/schema)."
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The run's controls after the change",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "400": {
            "description": "Refused (`problems`)"
          },
          "409": {
            "description": "Finished"
          },
          "307": {
            "description": "This node is a member; the leader answers"
          },
          "404": {
            "description": "Harness mode is off (RUSTYBIN_HARNESS=on), or no such run"
          },
          "403": {
            "description": "permission_required: the caller lacks harness.run"
          }
        },
        "x-rustybin-permission": "harness.run"
      }
    },
    "/_rustybin/harness/clusters/{id}/runs/{run}/start": {
      "post": {
        "tags": [
          "Harness"
        ],
        "summary": "Start a cluster run",
        "operationId": "startHarnessClusterRun",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "run",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "202": {
            "description": "Starting (synchronised)",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "409": {
            "description": "No quorum, a run is active, or the clients cannot carry the rate"
          },
          "404": {
            "description": "Harness mode is off (RUSTYBIN_HARNESS=on), or no such run"
          },
          "403": {
            "description": "permission_required: the caller lacks harness.run"
          }
        },
        "x-rustybin-permission": "harness.run"
      }
    },
    "/_rustybin/harness/clusters/{id}/runs/{run}/stop": {
      "post": {
        "tags": [
          "Harness"
        ],
        "summary": "Stop a cluster run",
        "operationId": "stopHarnessClusterRun",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "run",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "202": {
            "description": "Stopping",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "200": {
            "description": "Already stopped or finished",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "404": {
            "description": "Harness mode is off (RUSTYBIN_HARNESS=on), or no such run"
          },
          "403": {
            "description": "permission_required: the caller lacks harness.run"
          }
        },
        "x-rustybin-permission": "harness.run"
      }
    },
    "/_rustybin/harness/clusters/{id}/runs/{run}/report": {
      "get": {
        "tags": [
          "Harness"
        ],
        "summary": "Merged report of a cluster run",
        "operationId": "getHarnessClusterReport",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "run",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "format",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "enum": [
                "json",
                "text",
                "junit"
              ]
            }
          }
        ],
        "responses": {
          "200": {
            "description": "The report",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              },
              "text/plain": {
                "schema": {
                  "type": "string"
                }
              },
              "application/xml": {
                "schema": {
                  "type": "string"
                }
              }
            }
          },
          "409": {
            "description": "The run has not finished"
          },
          "404": {
            "description": "Harness mode is off (RUSTYBIN_HARNESS=on), or no such run"
          },
          "403": {
            "description": "permission_required: the caller lacks harness.read"
          }
        },
        "x-rustybin-permission": "harness.read"
      }
    },
    "/_rustybin/harness/import": {
      "post": {
        "tags": [
          "Harness"
        ],
        "summary": "A recording as a scenario's source",
        "description": "A HAR file, or the answer of GET /_rustybin/requests, as weighted request templates. Secret-looking headers and query parameters are removed and named; entries with a secret-looking field in the body are left out. Sends nothing.",
        "operationId": "importHarnessRecording",
        "responses": {
          "200": {
            "description": "`source.requests`, `entries`, `skipped`, `removed`, `hosts`",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "400": {
            "description": "Not a recording, or nothing to replay"
          },
          "403": {
            "description": "permission_required: the caller lacks harness.read"
          }
        },
        "x-rustybin-permission": "harness.read"
      }
    },
    "/_rustybin/harness/preview": {
      "post": {
        "tags": [
          "Harness"
        ],
        "summary": "Preview a scenario",
        "description": "The expected rate per second per layer and in total (users for closed layers), from the patterns' exact integrals, with the validation's problems. Sends nothing; works with harness mode off.",
        "operationId": "previewHarnessScenario",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/HarnessScenario"
              }
            },
            "application/yaml": {
              "schema": {
                "type": "string"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "`layers[].series`, `total`, `step_secs`, `valid`, `problems`",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "400": {
            "description": "Unparseable scenario"
          },
          "403": {
            "description": "permission_required: the caller lacks harness.read"
          }
        },
        "x-rustybin-permission": "harness.read"
      }
    },
    "/_rustybin/harness/runs/{run}/events": {
      "get": {
        "tags": [
          "Harness"
        ],
        "summary": "Run feed",
        "description": "Server-Sent Events: `snapshot` every second, `change` and `finding`, then `finished` with the report's summary.",
        "operationId": "harnessRunEvents",
        "parameters": [
          {
            "name": "run",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Server-Sent Events",
            "content": {
              "text/event-stream": {
                "schema": {
                  "type": "string"
                }
              }
            }
          },
          "404": {
            "description": "Harness mode is off (RUSTYBIN_HARNESS=on), or no such run"
          },
          "403": {
            "description": "permission_required: the caller lacks harness.read"
          }
        },
        "x-rustybin-permission": "harness.read"
      }
    },
    "/_rustybin/harness/clusters/{id}/runs/{run}/events": {
      "get": {
        "tags": [
          "Harness"
        ],
        "summary": "Cluster run feed",
        "description": "Server-Sent Events: `snapshot` every second, `change`, `finding`, `scale_request`, `leader_changed` (this node no longer leads; reconnect to the URL in the event), then `finished`.",
        "operationId": "harnessClusterRunEvents",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "run",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Server-Sent Events",
            "content": {
              "text/event-stream": {
                "schema": {
                  "type": "string"
                }
              }
            }
          },
          "307": {
            "description": "This node is a member; the leader answers"
          },
          "404": {
            "description": "Harness mode is off (RUSTYBIN_HARNESS=on), or no such run"
          },
          "403": {
            "description": "permission_required: the caller lacks harness.read"
          }
        },
        "x-rustybin-permission": "harness.read"
      }
    },
    "/_rustybin/metrics": {
      "get": {
        "tags": [
          "Control Plane"
        ],
        "summary": "Prometheus metrics",
        "description": "Prometheus text exposition (version 0.0.4): rustybin_requests_total{route,method,status_class}, rustybin_request_duration_seconds{route} (histogram, buckets 1 ms to 60 s), rustybin_streams_open, rustybin_egress_bytes_total, rustybin_protocol_requests_total{protocol}, rustybin_llm_tokens_total{provider,model_family,direction}, rustybin_llm_requests_total{provider,model_family,streaming}, rustybin_llm_faults_total{provider,kind}, rustybin_limit_rejections_total{dimension}, rustybin_faults_injected_total{kind}, rustybin_build_info{version,git_sha}; in harness mode rustybin_harness_requests_total{run,class,status}, rustybin_harness_latency_seconds{run,kind}, rustybin_harness_scheduler_lag_seconds{run}, rustybin_harness_inflight{run} and rustybin_harness_server_arrivals_total{run} (the run label is bounded to the active run plus the last 4); with API keys also rustybin_keys_active, rustybin_keys_last_sync_timestamp_seconds and (with a quota store) rustybin_quota_store_up. The route label is the matched route template.",
        "operationId": "getRustybinMetrics",
        "responses": {
          "200": {
            "description": "Metrics",
            "content": {
              "text/plain": {
                "schema": {
                  "type": "string"
                }
              }
            }
          },
          "401": {
            "description": "Control-plane authentication required (RUSTYBIN_CONTROL_AUTH token or jwt)"
          },
          "403": {
            "description": "permission_required: the caller lacks instance.read"
          }
        },
        "x-rustybin-permission": "instance.read"
      }
    },
    "/_rustybin/usage": {
      "get": {
        "tags": [
          "Control Plane"
        ],
        "summary": "Plan limits and current usage",
        "description": "The active plan (RUSTYBIN_PLAN), its limits and the usage of the current period. Session scope reports only the caller's own counters. Shared mode (RUSTYBIN_SHARED_MODE): called with an API key (X-Rustybin-Key or ?rb_key=, or a control JWT with scope inspector and claim rb_key) it reports that key's limits and today's usage (scope `key`, plan = the key's label). Exempt from every limit.",
        "operationId": "getRustybinUsage",
        "responses": {
          "200": {
            "description": "Usage",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "plan": {
                      "type": "string",
                      "description": "none, free, pro, team, enterprise or custom; in shared mode the key's label"
                    },
                    "active": {
                      "type": "boolean"
                    },
                    "scope": {
                      "type": "string",
                      "enum": [
                        "instance",
                        "session",
                        "key"
                      ]
                    },
                    "session": {
                      "type": "string",
                      "description": "Session scope only: the caller's session key"
                    },
                    "key_id": {
                      "type": "string",
                      "description": "Shared mode: the API key id"
                    },
                    "inspector": {
                      "type": "object",
                      "description": "Shared mode: the key's inspector retention",
                      "properties": {
                        "entries": {
                          "type": [
                            "integer",
                            "null"
                          ]
                        },
                        "ttl_secs": {
                          "type": [
                            "integer",
                            "null"
                          ]
                        }
                      }
                    },
                    "quota_store": {
                      "type": "string",
                      "enum": [
                        "local",
                        "postgres"
                      ],
                      "description": "Shared mode: where daily totals are shared"
                    },
                    "limits": {
                      "type": "object"
                    },
                    "period": {
                      "type": "object",
                      "properties": {
                        "kind": {
                          "type": "string",
                          "enum": [
                            "day",
                            "month"
                          ]
                        },
                        "start": {
                          "type": "string",
                          "format": "date-time"
                        },
                        "end": {
                          "type": "string",
                          "format": "date-time"
                        },
                        "resets_in_secs": {
                          "type": "integer"
                        }
                      }
                    },
                    "requests": {
                      "type": "object",
                      "properties": {
                        "used": {
                          "type": "integer"
                        },
                        "limit": {
                          "type": [
                            "integer",
                            "null"
                          ]
                        },
                        "remaining": {
                          "type": [
                            "integer",
                            "null"
                          ]
                        }
                      }
                    },
                    "egress": {
                      "type": "object",
                      "properties": {
                        "used_bytes": {
                          "type": "integer"
                        },
                        "limit_bytes": {
                          "type": [
                            "integer",
                            "null"
                          ]
                        },
                        "remaining_bytes": {
                          "type": [
                            "integer",
                            "null"
                          ]
                        }
                      }
                    },
                    "rate": {
                      "type": "object"
                    },
                    "in_flight": {
                      "type": "object"
                    },
                    "open_streams": {
                      "type": "object"
                    },
                    "persisted": {
                      "type": "boolean"
                    },
                    "instance_id": {
                      "type": "string"
                    },
                    "build": {
                      "type": "object",
                      "properties": {
                        "version": {
                          "type": "string"
                        },
                        "git_sha": {
                          "type": [
                            "string",
                            "null"
                          ]
                        },
                        "profile": {
                          "type": "string"
                        },
                        "rustc": {
                          "type": "string"
                        }
                      }
                    },
                    "control_auth": {
                      "type": "string",
                      "enum": [
                        "password",
                        "open",
                        "token",
                        "jwt"
                      ]
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "permission_required: the caller lacks instance.read"
          }
        },
        "x-rustybin-permission": "instance.read"
      }
    },
    "/_rustybin/keys/usage": {
      "get": {
        "tags": [
          "Control Plane"
        ],
        "summary": "Per-key daily usage",
        "description": "Per-key totals of one UTC day for a platform collector (shared mode or RUSTYBIN_REQUIRE_KEY). From the quota store when RUSTYBIN_QUOTA_STORE is set, else from this replica's in-memory counters (today and the two previous days). Sorted by key id; continue with ?after=<next_after>. Admin token required.",
        "operationId": "getRustybinKeysUsage",
        "parameters": [
          {
            "name": "day",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "format": "date"
            },
            "description": "UTC day, default today"
          },
          {
            "name": "after",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Return key ids greater than this one"
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 1000,
              "default": 1000
            }
          }
        ],
        "responses": {
          "200": {
            "description": "One page of per-key totals",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "day": {
                      "type": "string",
                      "format": "date"
                    },
                    "keys": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "key_id": {
                            "type": "string"
                          },
                          "requests": {
                            "type": "integer"
                          },
                          "egress_bytes": {
                            "type": "integer"
                          }
                        }
                      }
                    },
                    "next_after": {
                      "type": [
                        "string",
                        "null"
                      ]
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Invalid day, after or limit"
          },
          "401": {
            "description": "Admin token required"
          },
          "403": {
            "description": "Public or shared mode without an admin token"
          },
          "503": {
            "description": "The quota store is unavailable (rustybin_quota_store_unavailable)"
          }
        },
        "x-rustybin-permission": "settings.read"
      }
    },
    "/ui": {
      "get": {
        "tags": [
          "Docs"
        ],
        "summary": "Web console",
        "operationId": "getConsoleRedirect",
        "responses": {
          "307": {
            "description": "Redirect to /ui/"
          }
        }
      }
    },
    "/ui/": {
      "get": {
        "tags": [
          "Docs"
        ],
        "summary": "Web console entry page",
        "operationId": "getConsoleIndex",
        "responses": {
          "200": {
            "description": "HTML",
            "content": {
              "text/html": {
                "schema": {
                  "type": "string"
                }
              }
            }
          }
        }
      }
    },
    "/ui/{path}": {
      "get": {
        "tags": [
          "Docs"
        ],
        "summary": "Console asset (SPA fallback to index.html)",
        "operationId": "getConsoleAsset",
        "parameters": [
          {
            "name": "path",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Asset"
          },
          "304": {
            "description": "Not modified (If-None-Match)"
          },
          "404": {
            "description": "Unknown asset"
          }
        }
      }
    },
    "/_rustybin/catalog": {
      "get": {
        "tags": [
          "Control Plane"
        ],
        "summary": "Route catalogue",
        "operationId": "getRustybinCatalog",
        "responses": {
          "200": {
            "description": "Catalogue",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "count": {
                      "type": "integer"
                    },
                    "categories": {
                      "type": "array",
                      "items": {
                        "type": "object"
                      }
                    },
                    "endpoints": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "path": {
                            "type": "string"
                          },
                          "methods": {
                            "type": "array",
                            "items": {
                              "type": "string"
                            }
                          },
                          "category": {
                            "type": "string"
                          },
                          "summary": {
                            "type": "string"
                          },
                          "description": {
                            "type": "string"
                          },
                          "protocol": {
                            "type": "string",
                            "enum": [
                              "http",
                              "sse",
                              "websocket"
                            ]
                          },
                          "examples": {
                            "type": "array",
                            "items": {
                              "type": "object"
                            }
                          }
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "permission_required: the caller lacks instance.read"
          }
        },
        "x-rustybin-permission": "instance.read"
      }
    },
    "/_rustybin/status": {
      "get": {
        "tags": [
          "Control Plane"
        ],
        "summary": "Instance status",
        "operationId": "getRustybinStatus",
        "responses": {
          "200": {
            "description": "Status",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "403": {
            "description": "permission_required: the caller lacks instance.read"
          }
        },
        "x-rustybin-permission": "instance.read"
      }
    },
    "/bin": {
      "get": {
        "tags": [
          "Request Bin"
        ],
        "summary": "List the caller's bins",
        "operationId": "listBins",
        "responses": {
          "200": {
            "description": "Bins of the caller's session"
          }
        }
      },
      "post": {
        "tags": [
          "Request Bin"
        ],
        "summary": "Create a request bin",
        "operationId": "createBin",
        "requestBody": {
          "required": false,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "status": {
                    "type": "integer",
                    "minimum": 200,
                    "maximum": 599
                  },
                  "headers": {
                    "type": "object",
                    "additionalProperties": {
                      "type": "string"
                    }
                  },
                  "body": {
                    "description": "String returned verbatim, any other JSON value is serialised"
                  },
                  "delay_ms": {
                    "type": "integer",
                    "minimum": 0
                  }
                }
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Bin created (id, URLs, expiry, limits)"
          },
          "400": {
            "description": "Invalid response definition"
          },
          "429": {
            "description": "Too many bins for this session"
          },
          "503": {
            "description": "Store full (public mode)"
          }
        }
      }
    },
    "/bin/{id}": {
      "parameters": [
        {
          "name": "id",
          "in": "path",
          "required": true,
          "schema": {
            "type": "string"
          },
          "description": "Bin id returned by POST /bin"
        }
      ],
      "post": {
        "tags": [
          "Request Bin"
        ],
        "summary": "Capture a request",
        "operationId": "captureBin",
        "requestBody": {
          "required": false,
          "content": {
            "*/*": {
              "schema": {}
            }
          }
        },
        "responses": {
          "200": {
            "description": "The bin's configured response (status, headers and body are configurable)"
          },
          "404": {
            "description": "Unknown or expired bin"
          }
        }
      },
      "delete": {
        "tags": [
          "Request Bin"
        ],
        "summary": "Delete the bin",
        "operationId": "deleteBin",
        "responses": {
          "200": {
            "description": "Deleted"
          },
          "404": {
            "description": "Unknown or expired bin"
          }
        }
      },
      "get": {
        "tags": [
          "Request Bin"
        ],
        "summary": "Capture a request",
        "operationId": "captureBin_get",
        "responses": {
          "200": {
            "description": "The bin's configured response (status, headers and body are configurable)"
          },
          "404": {
            "description": "Unknown or expired bin"
          }
        }
      },
      "put": {
        "tags": [
          "Request Bin"
        ],
        "summary": "Capture a request",
        "operationId": "captureBin_put",
        "requestBody": {
          "required": false,
          "content": {
            "*/*": {
              "schema": {}
            }
          }
        },
        "responses": {
          "200": {
            "description": "The bin's configured response (status, headers and body are configurable)"
          },
          "404": {
            "description": "Unknown or expired bin"
          }
        }
      },
      "patch": {
        "tags": [
          "Request Bin"
        ],
        "summary": "Capture a request",
        "operationId": "captureBin_patch",
        "requestBody": {
          "required": false,
          "content": {
            "*/*": {
              "schema": {}
            }
          }
        },
        "responses": {
          "200": {
            "description": "The bin's configured response (status, headers and body are configurable)"
          },
          "404": {
            "description": "Unknown or expired bin"
          }
        }
      }
    },
    "/bin/{id}/{path}": {
      "parameters": [
        {
          "name": "id",
          "in": "path",
          "required": true,
          "schema": {
            "type": "string"
          },
          "description": "Bin id returned by POST /bin"
        },
        {
          "name": "path",
          "in": "path",
          "required": true,
          "schema": {
            "type": "string"
          },
          "description": "Any sub path"
        }
      ],
      "post": {
        "tags": [
          "Request Bin"
        ],
        "summary": "Capture a request",
        "operationId": "captureBinPath",
        "requestBody": {
          "required": false,
          "content": {
            "*/*": {
              "schema": {}
            }
          }
        },
        "responses": {
          "200": {
            "description": "The bin's configured response (status, headers and body are configurable)"
          },
          "404": {
            "description": "Unknown or expired bin"
          }
        }
      },
      "get": {
        "tags": [
          "Request Bin"
        ],
        "summary": "Capture a request",
        "operationId": "captureBinPath_get",
        "responses": {
          "200": {
            "description": "The bin's configured response (status, headers and body are configurable)"
          },
          "404": {
            "description": "Unknown or expired bin"
          }
        }
      },
      "put": {
        "tags": [
          "Request Bin"
        ],
        "summary": "Capture a request",
        "operationId": "captureBinPath_put",
        "requestBody": {
          "required": false,
          "content": {
            "*/*": {
              "schema": {}
            }
          }
        },
        "responses": {
          "200": {
            "description": "The bin's configured response (status, headers and body are configurable)"
          },
          "404": {
            "description": "Unknown or expired bin"
          }
        }
      },
      "patch": {
        "tags": [
          "Request Bin"
        ],
        "summary": "Capture a request",
        "operationId": "captureBinPath_patch",
        "requestBody": {
          "required": false,
          "content": {
            "*/*": {
              "schema": {}
            }
          }
        },
        "responses": {
          "200": {
            "description": "The bin's configured response (status, headers and body are configurable)"
          },
          "404": {
            "description": "Unknown or expired bin"
          }
        }
      },
      "delete": {
        "tags": [
          "Request Bin"
        ],
        "summary": "Capture a request",
        "operationId": "captureBinPath_delete",
        "responses": {
          "200": {
            "description": "The bin's configured response (status, headers and body are configurable)"
          },
          "404": {
            "description": "Unknown or expired bin"
          }
        }
      }
    },
    "/bin/{id}/requests": {
      "get": {
        "tags": [
          "Request Bin"
        ],
        "summary": "List captured requests",
        "operationId": "listBinRequests",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Bin id returned by POST /bin"
          },
          {
            "name": "limit",
            "in": "query",
            "schema": {
              "type": "integer",
              "default": 50
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Bin summary and requests, newest first"
          },
          "404": {
            "description": "Unknown or expired bin"
          }
        }
      }
    },
    "/bin/{id}/requests/stream": {
      "get": {
        "tags": [
          "Request Bin"
        ],
        "summary": "Live feed of captured requests (SSE)",
        "operationId": "streamBinRequests",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Bin id returned by POST /bin"
          },
          {
            "name": "Last-Event-ID",
            "in": "header",
            "schema": {
              "type": "integer"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "text/event-stream of `request` events",
            "content": {
              "text/event-stream": {}
            }
          },
          "404": {
            "description": "Unknown or expired bin"
          }
        }
      }
    },
    "/bin/{id}/requests/{n}": {
      "get": {
        "tags": [
          "Request Bin"
        ],
        "summary": "One captured request",
        "operationId": "getBinRequest",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Bin id returned by POST /bin"
          },
          {
            "name": "n",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Captured request"
          },
          "404": {
            "description": "Unknown bin or request"
          }
        }
      }
    },
    "/mock/{name}": {
      "post": {
        "tags": [
          "Mocks"
        ],
        "summary": "Call a mock",
        "operationId": "callMock",
        "parameters": [
          {
            "name": "name",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Mock name"
          }
        ],
        "requestBody": {
          "required": false,
          "content": {
            "*/*": {
              "schema": {}
            }
          }
        },
        "responses": {
          "200": {
            "description": "The mocked response (status, headers and body follow the mock's spec)"
          },
          "400": {
            "description": "Request does not match the spec (validation enforce)"
          },
          "401": {
            "description": "Mocked security rejected the request"
          },
          "404": {
            "description": "Unknown mock or no matching operation"
          },
          "405": {
            "description": "Method not documented for this path"
          },
          "503": {
            "description": "Mock switched off or not deployed"
          }
        }
      },
      "get": {
        "tags": [
          "Mocks"
        ],
        "summary": "Call a mock",
        "operationId": "callMock_get",
        "parameters": [
          {
            "name": "name",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Mock name"
          }
        ],
        "responses": {
          "200": {
            "description": "The mocked response (status, headers and body follow the mock's spec)"
          },
          "400": {
            "description": "Request does not match the spec (validation enforce)"
          },
          "401": {
            "description": "Mocked security rejected the request"
          },
          "404": {
            "description": "Unknown mock or no matching operation"
          },
          "405": {
            "description": "Method not documented for this path"
          },
          "503": {
            "description": "Mock switched off or not deployed"
          }
        }
      },
      "put": {
        "tags": [
          "Mocks"
        ],
        "summary": "Call a mock",
        "operationId": "callMock_put",
        "parameters": [
          {
            "name": "name",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Mock name"
          }
        ],
        "requestBody": {
          "required": false,
          "content": {
            "*/*": {
              "schema": {}
            }
          }
        },
        "responses": {
          "200": {
            "description": "The mocked response (status, headers and body follow the mock's spec)"
          },
          "400": {
            "description": "Request does not match the spec (validation enforce)"
          },
          "401": {
            "description": "Mocked security rejected the request"
          },
          "404": {
            "description": "Unknown mock or no matching operation"
          },
          "405": {
            "description": "Method not documented for this path"
          },
          "503": {
            "description": "Mock switched off or not deployed"
          }
        }
      },
      "patch": {
        "tags": [
          "Mocks"
        ],
        "summary": "Call a mock",
        "operationId": "callMock_patch",
        "parameters": [
          {
            "name": "name",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Mock name"
          }
        ],
        "requestBody": {
          "required": false,
          "content": {
            "*/*": {
              "schema": {}
            }
          }
        },
        "responses": {
          "200": {
            "description": "The mocked response (status, headers and body follow the mock's spec)"
          },
          "400": {
            "description": "Request does not match the spec (validation enforce)"
          },
          "401": {
            "description": "Mocked security rejected the request"
          },
          "404": {
            "description": "Unknown mock or no matching operation"
          },
          "405": {
            "description": "Method not documented for this path"
          },
          "503": {
            "description": "Mock switched off or not deployed"
          }
        }
      },
      "delete": {
        "tags": [
          "Mocks"
        ],
        "summary": "Call a mock",
        "operationId": "callMock_delete",
        "parameters": [
          {
            "name": "name",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Mock name"
          }
        ],
        "responses": {
          "200": {
            "description": "The mocked response (status, headers and body follow the mock's spec)"
          },
          "400": {
            "description": "Request does not match the spec (validation enforce)"
          },
          "401": {
            "description": "Mocked security rejected the request"
          },
          "404": {
            "description": "Unknown mock or no matching operation"
          },
          "405": {
            "description": "Method not documented for this path"
          },
          "503": {
            "description": "Mock switched off or not deployed"
          }
        }
      }
    },
    "/mock/{name}/{path}": {
      "post": {
        "tags": [
          "Mocks"
        ],
        "summary": "Call a mock",
        "operationId": "callMockPath",
        "parameters": [
          {
            "name": "name",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Mock name"
          },
          {
            "name": "path",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Path below the mock root"
          }
        ],
        "requestBody": {
          "required": false,
          "content": {
            "*/*": {
              "schema": {}
            }
          }
        },
        "responses": {
          "200": {
            "description": "The mocked response (status, headers and body follow the mock's spec)"
          },
          "400": {
            "description": "Request does not match the spec (validation enforce)"
          },
          "401": {
            "description": "Mocked security rejected the request"
          },
          "404": {
            "description": "Unknown mock or no matching operation"
          },
          "405": {
            "description": "Method not documented for this path"
          },
          "503": {
            "description": "Mock switched off or not deployed"
          }
        }
      },
      "get": {
        "tags": [
          "Mocks"
        ],
        "summary": "Call a mock",
        "operationId": "callMockPath_get",
        "parameters": [
          {
            "name": "name",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Mock name"
          },
          {
            "name": "path",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Path below the mock root"
          }
        ],
        "responses": {
          "200": {
            "description": "The mocked response (status, headers and body follow the mock's spec)"
          },
          "400": {
            "description": "Request does not match the spec (validation enforce)"
          },
          "401": {
            "description": "Mocked security rejected the request"
          },
          "404": {
            "description": "Unknown mock or no matching operation"
          },
          "405": {
            "description": "Method not documented for this path"
          },
          "503": {
            "description": "Mock switched off or not deployed"
          }
        }
      },
      "put": {
        "tags": [
          "Mocks"
        ],
        "summary": "Call a mock",
        "operationId": "callMockPath_put",
        "parameters": [
          {
            "name": "name",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Mock name"
          },
          {
            "name": "path",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Path below the mock root"
          }
        ],
        "requestBody": {
          "required": false,
          "content": {
            "*/*": {
              "schema": {}
            }
          }
        },
        "responses": {
          "200": {
            "description": "The mocked response (status, headers and body follow the mock's spec)"
          },
          "400": {
            "description": "Request does not match the spec (validation enforce)"
          },
          "401": {
            "description": "Mocked security rejected the request"
          },
          "404": {
            "description": "Unknown mock or no matching operation"
          },
          "405": {
            "description": "Method not documented for this path"
          },
          "503": {
            "description": "Mock switched off or not deployed"
          }
        }
      },
      "patch": {
        "tags": [
          "Mocks"
        ],
        "summary": "Call a mock",
        "operationId": "callMockPath_patch",
        "parameters": [
          {
            "name": "name",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Mock name"
          },
          {
            "name": "path",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Path below the mock root"
          }
        ],
        "requestBody": {
          "required": false,
          "content": {
            "*/*": {
              "schema": {}
            }
          }
        },
        "responses": {
          "200": {
            "description": "The mocked response (status, headers and body follow the mock's spec)"
          },
          "400": {
            "description": "Request does not match the spec (validation enforce)"
          },
          "401": {
            "description": "Mocked security rejected the request"
          },
          "404": {
            "description": "Unknown mock or no matching operation"
          },
          "405": {
            "description": "Method not documented for this path"
          },
          "503": {
            "description": "Mock switched off or not deployed"
          }
        }
      },
      "delete": {
        "tags": [
          "Mocks"
        ],
        "summary": "Call a mock",
        "operationId": "callMockPath_delete",
        "parameters": [
          {
            "name": "name",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Mock name"
          },
          {
            "name": "path",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Path below the mock root"
          }
        ],
        "responses": {
          "200": {
            "description": "The mocked response (status, headers and body follow the mock's spec)"
          },
          "400": {
            "description": "Request does not match the spec (validation enforce)"
          },
          "401": {
            "description": "Mocked security rejected the request"
          },
          "404": {
            "description": "Unknown mock or no matching operation"
          },
          "405": {
            "description": "Method not documented for this path"
          },
          "503": {
            "description": "Mock switched off or not deployed"
          }
        }
      }
    },
    "/mock/{name}/_rustybin/openapi.json": {
      "get": {
        "tags": [
          "Mocks"
        ],
        "summary": "Deployed spec (JSON)",
        "operationId": "getMockSpec",
        "parameters": [
          {
            "name": "name",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Mock name"
          }
        ],
        "responses": {
          "200": {
            "description": "OK"
          },
          "404": {
            "description": "Unknown mock"
          }
        }
      }
    },
    "/mock/{name}/_rustybin/openapi.yaml": {
      "get": {
        "tags": [
          "Mocks"
        ],
        "summary": "Deployed spec (YAML)",
        "operationId": "getMockSpecYaml",
        "parameters": [
          {
            "name": "name",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Mock name"
          }
        ],
        "responses": {
          "200": {
            "description": "OK"
          },
          "404": {
            "description": "Unknown mock"
          }
        }
      }
    },
    "/_rustybin/mocks": {
      "get": {
        "tags": [
          "Mocks"
        ],
        "summary": "List mocks",
        "operationId": "listMocks",
        "parameters": [
          {
            "name": "owner",
            "in": "query",
            "required": false,
            "description": "all: every visitor's mocks too (admin)",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "project",
            "in": "query",
            "required": false,
            "description": "One project's mocks (instance: the instance's without one)",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK"
          },
          "404": {
            "description": "Unknown mock"
          },
          "403": {
            "description": "permission_required: the caller lacks mocks.read"
          }
        },
        "x-rustybin-permission": "mocks.read"
      },
      "post": {
        "tags": [
          "Mocks"
        ],
        "summary": "Create a mock from an OpenAPI spec",
        "operationId": "createMock",
        "parameters": [],
        "responses": {
          "201": {
            "description": "Created (details)"
          },
          "400": {
            "description": "Invalid spec or settings"
          },
          "409": {
            "description": "Name taken"
          },
          "422": {
            "description": "Deploy checks failed (report)"
          },
          "403": {
            "description": "permission_required: the caller lacks mocks.write"
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "spec"
                ],
                "properties": {
                  "spec": {
                    "description": "OpenAPI 3.0/3.1 document (text or object)"
                  },
                  "name": {
                    "type": "string",
                    "pattern": "^[a-z0-9]([a-z0-9-]{0,38}[a-z0-9])?$"
                  },
                  "enabled": {
                    "type": "boolean"
                  },
                  "deploy": {
                    "type": "boolean",
                    "default": true
                  },
                  "force": {
                    "type": "boolean"
                  },
                  "strip_server_prefix": {
                    "type": "boolean"
                  },
                  "responses": {
                    "type": "object"
                  },
                  "security": {
                    "type": "object"
                  },
                  "operations": {
                    "type": "object"
                  },
                  "mcp": {
                    "type": "object",
                    "description": "{enabled, exclude}: the mock's MCP server"
                  },
                  "project": {
                    "type": "string",
                    "description": "The project it belongs to (mocks.write there); absent: the instance's, or the one project the caller works in"
                  }
                }
              }
            }
          }
        },
        "x-rustybin-permission": "mocks.write"
      }
    },
    "/_rustybin/mocks/import": {
      "post": {
        "tags": [
          "Mocks"
        ],
        "summary": "Preview a spec",
        "operationId": "previewMockSpec",
        "parameters": [],
        "responses": {
          "200": {
            "description": "OK"
          },
          "404": {
            "description": "Unknown mock"
          },
          "403": {
            "description": "permission_required: the caller lacks mocks.read"
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "spec": {}
                }
              }
            }
          }
        },
        "x-rustybin-permission": "mocks.read"
      }
    },
    "/_rustybin/mocks/apply": {
      "post": {
        "tags": [
          "Mocks"
        ],
        "summary": "Apply a rustybin.yaml document",
        "operationId": "applyMocks",
        "parameters": [
          {
            "name": "prune",
            "in": "query",
            "schema": {
              "type": "boolean"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK"
          },
          "401": {
            "description": "Control-plane credentials required"
          },
          "403": {
            "description": "Admin token or admin scope required"
          },
          "404": {
            "description": "Unknown mock"
          }
        },
        "x-rustybin-permission": "config.apply"
      }
    },
    "/_rustybin/mocks/reload": {
      "post": {
        "tags": [
          "Mocks"
        ],
        "summary": "Reload file-defined mocks",
        "operationId": "reloadMocks",
        "parameters": [],
        "responses": {
          "200": {
            "description": "OK"
          },
          "401": {
            "description": "Control-plane credentials required"
          },
          "403": {
            "description": "Admin token or admin scope required"
          },
          "404": {
            "description": "Unknown mock"
          }
        },
        "x-rustybin-permission": "config.apply"
      }
    },
    "/_rustybin/mocks/export": {
      "get": {
        "tags": [
          "Mocks"
        ],
        "summary": "Export mocks as YAML",
        "operationId": "exportMocks",
        "parameters": [],
        "responses": {
          "200": {
            "description": "OK"
          },
          "404": {
            "description": "Unknown mock"
          },
          "403": {
            "description": "permission_required: the caller lacks mocks.read"
          }
        },
        "x-rustybin-permission": "mocks.read"
      }
    },
    "/_rustybin/mocks/import/fetch": {
      "post": {
        "tags": [
          "Mocks"
        ],
        "summary": "Fetch a spec from a URL on the server",
        "operationId": "fetchMockSpec",
        "parameters": [],
        "responses": {
          "200": {
            "description": "OK"
          },
          "404": {
            "description": "Unknown mock"
          },
          "403": {
            "description": "permission_required: the caller lacks mocks.write"
          }
        },
        "x-rustybin-permission": "mocks.write"
      }
    },
    "/_rustybin/mocks/config.schema.json": {
      "get": {
        "tags": [
          "Mocks"
        ],
        "summary": "JSON Schema of rustybin.yaml",
        "operationId": "getMocksConfigSchema",
        "parameters": [],
        "responses": {
          "200": {
            "description": "OK"
          },
          "404": {
            "description": "Unknown mock"
          },
          "403": {
            "description": "permission_required: the caller lacks mocks.read"
          }
        },
        "x-rustybin-permission": "mocks.read"
      }
    },
    "/_rustybin/mocks/{name}": {
      "get": {
        "tags": [
          "Mocks"
        ],
        "summary": "Mock details",
        "operationId": "getMock",
        "parameters": [
          {
            "name": "name",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Mock name"
          }
        ],
        "responses": {
          "200": {
            "description": "OK"
          },
          "404": {
            "description": "Unknown mock"
          },
          "403": {
            "description": "permission_required: the caller lacks mocks.read"
          }
        },
        "x-rustybin-permission": "mocks.read"
      },
      "patch": {
        "tags": [
          "Mocks"
        ],
        "summary": "Edit the draft",
        "operationId": "updateMock",
        "parameters": [
          {
            "name": "name",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Mock name"
          }
        ],
        "responses": {
          "200": {
            "description": "OK"
          },
          "401": {
            "description": "Control-plane credentials required"
          },
          "403": {
            "description": "Admin token or admin scope required"
          },
          "404": {
            "description": "Unknown mock"
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "project": {
                    "type": [
                      "string",
                      "null"
                    ],
                    "description": "Move the mock to this project (null or instance: the instance's); mocks.write in both"
                  }
                }
              }
            }
          }
        },
        "x-rustybin-permission": "mocks.write"
      },
      "delete": {
        "tags": [
          "Mocks"
        ],
        "summary": "Delete a mock",
        "operationId": "deleteMock",
        "parameters": [
          {
            "name": "name",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Mock name"
          }
        ],
        "responses": {
          "200": {
            "description": "OK"
          },
          "401": {
            "description": "Control-plane credentials required"
          },
          "403": {
            "description": "Admin token or admin scope required"
          },
          "404": {
            "description": "Unknown mock"
          }
        },
        "x-rustybin-permission": "mocks.delete"
      }
    },
    "/_rustybin/mocks/{name}/enable": {
      "post": {
        "tags": [
          "Mocks"
        ],
        "summary": "Switch on",
        "operationId": "enableMock",
        "parameters": [
          {
            "name": "name",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Mock name"
          }
        ],
        "responses": {
          "200": {
            "description": "OK"
          },
          "401": {
            "description": "Control-plane credentials required"
          },
          "403": {
            "description": "Admin token or admin scope required"
          },
          "404": {
            "description": "Unknown mock"
          }
        },
        "x-rustybin-permission": "mocks.write"
      }
    },
    "/_rustybin/mocks/{name}/disable": {
      "post": {
        "tags": [
          "Mocks"
        ],
        "summary": "Switch off",
        "operationId": "disableMock",
        "parameters": [
          {
            "name": "name",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Mock name"
          }
        ],
        "responses": {
          "200": {
            "description": "OK"
          },
          "401": {
            "description": "Control-plane credentials required"
          },
          "403": {
            "description": "Admin token or admin scope required"
          },
          "404": {
            "description": "Unknown mock"
          }
        },
        "x-rustybin-permission": "mocks.write"
      }
    },
    "/_rustybin/mocks/{name}/deploy": {
      "post": {
        "tags": [
          "Mocks"
        ],
        "summary": "Deploy the draft",
        "operationId": "deployMock",
        "parameters": [
          {
            "name": "name",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Mock name"
          },
          {
            "name": "force",
            "in": "query",
            "schema": {
              "type": "boolean"
            }
          },
          {
            "name": "If-Match",
            "in": "header",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "The draft revision to deploy (the mock's ETag): 409 rustybin_stale_revision when the draft has moved on"
          }
        ],
        "responses": {
          "200": {
            "description": "OK"
          },
          "401": {
            "description": "Control-plane credentials required"
          },
          "403": {
            "description": "Admin token or admin scope required"
          },
          "404": {
            "description": "Unknown mock"
          },
          "409": {
            "description": "rustybin_stale_revision: the draft is no longer the revision named"
          },
          "422": {
            "description": "The deploy checks found errors (deploy with force)"
          }
        },
        "requestBody": {
          "required": false,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "additionalProperties": false,
                "properties": {
                  "expected_revision": {
                    "type": "integer",
                    "description": "The draft revision to deploy (else If-Match; both must agree)"
                  }
                }
              }
            }
          }
        },
        "x-rustybin-permission": "mocks.write"
      }
    },
    "/_rustybin/mocks/{name}/rollback": {
      "post": {
        "tags": [
          "Mocks"
        ],
        "summary": "Roll back",
        "operationId": "rollbackMock",
        "parameters": [
          {
            "name": "name",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Mock name"
          }
        ],
        "responses": {
          "200": {
            "description": "OK"
          },
          "401": {
            "description": "Control-plane credentials required"
          },
          "403": {
            "description": "Admin token or admin scope required"
          },
          "404": {
            "description": "Unknown mock"
          }
        },
        "x-rustybin-permission": "mocks.write"
      }
    },
    "/_rustybin/mocks/{name}/report": {
      "get": {
        "tags": [
          "Mocks"
        ],
        "summary": "Deploy-check report",
        "operationId": "getMockReport",
        "parameters": [
          {
            "name": "name",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Mock name"
          }
        ],
        "responses": {
          "200": {
            "description": "OK"
          },
          "404": {
            "description": "Unknown mock"
          },
          "403": {
            "description": "permission_required: the caller lacks mocks.read"
          }
        },
        "x-rustybin-permission": "mocks.read"
      }
    },
    "/_rustybin/mocks/{name}/coverage": {
      "get": {
        "tags": [
          "Mocks"
        ],
        "summary": "Example coverage: which operations have an example for their success responses (draft and live)",
        "operationId": "getMockCoverage",
        "parameters": [
          {
            "name": "name",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Mock name"
          }
        ],
        "responses": {
          "200": {
            "description": "OK"
          },
          "404": {
            "description": "Unknown mock"
          },
          "403": {
            "description": "permission_required: the caller lacks mocks.read"
          }
        },
        "x-rustybin-permission": "mocks.read"
      }
    },
    "/_rustybin/mocks/ai/spec": {
      "post": {
        "tags": [
          "Mocks"
        ],
        "summary": "AI: an OpenAPI document from a description",
        "description": "Runs the assist task spec_from_description on the configured provider: the document on the chosen version (3.1.0, 3.0.3, 2.0) with the style options, parsed and checked, plus its preview (as POST /_rustybin/mocks/import gives). Nothing is created. Streamed as SSE (events progress, usage, result, error, done) with Accept: text/event-stream or stream: true, else one JSON document. Operator only, unless RUSTYBIN_ASSIST_VISITORS.",
        "operationId": "aiSpecFromDescription",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "description"
                ],
                "properties": {
                  "description": {
                    "type": "string"
                  },
                  "openapi_version": {
                    "type": "string",
                    "enum": [
                      "3.1.0",
                      "3.0.3",
                      "2.0"
                    ]
                  },
                  "style": {
                    "type": "object",
                    "properties": {
                      "auth": {
                        "type": "string",
                        "enum": [
                          "none",
                          "api_key",
                          "bearer",
                          "oauth2"
                        ]
                      },
                      "pagination": {
                        "type": "string",
                        "enum": [
                          "none",
                          "page",
                          "cursor"
                        ]
                      },
                      "errors": {
                        "type": "string",
                        "enum": [
                          "problem",
                          "simple"
                        ]
                      }
                    }
                  },
                  "model": {
                    "type": "string"
                  },
                  "stream": {
                    "type": "boolean"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "{spec, text, preview, usage, sent}"
          },
          "403": {
            "description": "Visitors need RUSTYBIN_ASSIST_VISITORS"
          },
          "429": {
            "description": "The caller's AI calls per minute"
          },
          "502": {
            "description": "The provider failed or the document never passed the checks"
          },
          "503": {
            "description": "No AI provider or key"
          }
        },
        "x-rustybin-permission": "assist.jobs"
      }
    },
    "/_rustybin/mocks/{name}/ai/examples": {
      "post": {
        "tags": [
          "Mocks"
        ],
        "summary": "AI: examples for the operations that lack them",
        "description": "Runs examples_for_operations in batches of 10 (source ai), or the deterministic generator (source generated, no key). Every example is validated against its response schema. With apply the examples are stored in the draft (operations.<id>.examples, source ai or generated); a person's examples stay.",
        "operationId": "aiExamplesForMock",
        "parameters": [
          {
            "name": "name",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Mock name"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "operations": {
                    "type": "array",
                    "items": {
                      "type": "string"
                    },
                    "description": "operationIds (default: every operation without examples)"
                  },
                  "per_response": {
                    "type": "integer",
                    "minimum": 1,
                    "maximum": 3
                  },
                  "persona": {
                    "type": "string"
                  },
                  "source": {
                    "type": "string",
                    "enum": [
                      "ai",
                      "generated"
                    ]
                  },
                  "apply": {
                    "type": "boolean"
                  },
                  "model": {
                    "type": "string"
                  },
                  "stream": {
                    "type": "boolean"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "{examples, source, applied, stored, coverage, usage}"
          },
          "404": {
            "description": "Unknown mock"
          },
          "409": {
            "description": "Every operation has examples"
          },
          "503": {
            "description": "No AI provider or key"
          },
          "403": {
            "description": "permission_required: the caller lacks assist.jobs"
          }
        },
        "x-rustybin-permission": "assist.jobs"
      }
    },
    "/_rustybin/mocks/{name}/ai/edit": {
      "post": {
        "tags": [
          "Mocks"
        ],
        "summary": "AI: edit the spec with an instruction",
        "description": "Runs edit_spec: the whole document after the instruction, parsed and checked, with a structural diff (operations added, removed, changed; at most 40 percent removed without an explicit ask). With apply the new document becomes the draft.",
        "operationId": "aiEditMock",
        "parameters": [
          {
            "name": "name",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Mock name"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "instruction"
                ],
                "properties": {
                  "instruction": {
                    "type": "string"
                  },
                  "apply": {
                    "type": "boolean"
                  },
                  "model": {
                    "type": "string"
                  },
                  "stream": {
                    "type": "boolean"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "{spec, text, before_text, diff, preview, applied, detail?, usage, sent}"
          },
          "404": {
            "description": "Unknown mock"
          },
          "502": {
            "description": "The provider failed or the edit never passed the checks"
          },
          "503": {
            "description": "No AI provider or key"
          },
          "403": {
            "description": "permission_required: the caller lacks assist.jobs"
          }
        },
        "x-rustybin-permission": "assist.jobs"
      }
    },
    "/_rustybin/mocks/{name}/export": {
      "get": {
        "tags": [
          "Mocks"
        ],
        "summary": "Export one mock",
        "operationId": "exportMock",
        "parameters": [
          {
            "name": "name",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Mock name"
          }
        ],
        "responses": {
          "200": {
            "description": "OK"
          },
          "404": {
            "description": "Unknown mock"
          },
          "403": {
            "description": "permission_required: the caller lacks mocks.read"
          }
        },
        "x-rustybin-permission": "mocks.read"
      }
    },
    "/_rustybin/mocks/{name}/spec": {
      "get": {
        "tags": [
          "Mocks"
        ],
        "summary": "The spec as uploaded",
        "operationId": "getMockSpecSource",
        "parameters": [
          {
            "name": "name",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Mock name"
          }
        ],
        "responses": {
          "200": {
            "description": "OK"
          },
          "404": {
            "description": "Unknown mock"
          },
          "403": {
            "description": "permission_required: the caller lacks mocks.read"
          }
        },
        "x-rustybin-permission": "mocks.read"
      }
    },
    "/_rustybin/mocks/{name}/revisions/{revision}": {
      "get": {
        "tags": [
          "Mocks"
        ],
        "summary": "A kept revision of a mock",
        "description": "A revision the mock still keeps: the draft, the live revision, the last deployed ones (5, 2 in public mode) and as many drafts replaced before they were deployed. Its spec as uploaded, its settings (secrets redacted unless the caller may change the mock) and changes_to_draft, what the current draft changes since (the sections a 409 rustybin_stale_revision names). Read like the mock: another visitor's mock is 404.",
        "operationId": "getMockRevision",
        "parameters": [
          {
            "name": "name",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Mock name"
          },
          {
            "name": "revision",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer",
              "minimum": 0
            }
          }
        ],
        "responses": {
          "200": {
            "description": "{name, revision, created_at, draft, live, current_draft_revision, changes_to_draft, spec: {format, openapi, title, version, text}, operations, settings, secrets_hidden}"
          },
          "400": {
            "description": "Not a revision number"
          },
          "404": {
            "description": "No such mock, or the revision is no longer kept"
          },
          "403": {
            "description": "permission_required: the caller lacks mocks.read"
          }
        },
        "x-rustybin-permission": "mocks.read"
      }
    },
    "/_rustybin/mocks/{name}/duplicate": {
      "post": {
        "tags": [
          "Mocks"
        ],
        "summary": "Copy a mock",
        "operationId": "duplicateMock",
        "parameters": [
          {
            "name": "name",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Mock name"
          }
        ],
        "responses": {
          "200": {
            "description": "OK"
          },
          "401": {
            "description": "Control-plane credentials required"
          },
          "403": {
            "description": "Admin token or admin scope required"
          },
          "404": {
            "description": "Unknown mock"
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "name": {
                    "type": "string"
                  }
                }
              }
            }
          }
        },
        "x-rustybin-permission": "mocks.write"
      }
    },
    "/_rustybin/mocks/{name}/state": {
      "get": {
        "tags": [
          "Mocks"
        ],
        "summary": "Stored items (stateful mode)",
        "operationId": "getMockState",
        "parameters": [
          {
            "name": "name",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Mock name"
          }
        ],
        "responses": {
          "200": {
            "description": "OK"
          },
          "404": {
            "description": "Unknown mock"
          },
          "403": {
            "description": "permission_required: the caller lacks mocks.read"
          }
        },
        "x-rustybin-permission": "mocks.read"
      },
      "delete": {
        "tags": [
          "Mocks"
        ],
        "summary": "Reset stored items",
        "operationId": "clearMockState",
        "parameters": [
          {
            "name": "name",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Mock name"
          }
        ],
        "responses": {
          "200": {
            "description": "OK"
          },
          "401": {
            "description": "Control-plane credentials required"
          },
          "403": {
            "description": "Admin token or admin scope required"
          },
          "404": {
            "description": "Unknown mock"
          }
        },
        "x-rustybin-permission": "mocks.data"
      }
    },
    "/_rustybin/mocks/{name}/collections/{format}": {
      "get": {
        "tags": [
          "Mocks"
        ],
        "summary": "The mock as a collection",
        "operationId": "getMockCollection",
        "parameters": [
          {
            "name": "name",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Mock name"
          },
          {
            "name": "format",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "enum": [
                "postman",
                "hurl",
                "curl",
                "http",
                "k6",
                "bruno",
                "insomnia"
              ]
            }
          },
          {
            "name": "base_url",
            "in": "query",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK"
          },
          "404": {
            "description": "Unknown mock"
          },
          "403": {
            "description": "permission_required: the caller lacks mocks.read"
          }
        },
        "x-rustybin-permission": "mocks.read"
      }
    },
    "/_rustybin/mocks/{name}/operations/{op}/rules/test": {
      "post": {
        "tags": [
          "Mocks"
        ],
        "summary": "Which rule would answer a captured call",
        "operationId": "testMockRules",
        "parameters": [
          {
            "name": "name",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Mock name"
          },
          {
            "name": "op",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "operationId"
          }
        ],
        "responses": {
          "200": {
            "description": "OK"
          },
          "404": {
            "description": "Unknown mock"
          },
          "403": {
            "description": "permission_required: the caller lacks mocks.read"
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "rules": {
                    "type": "array"
                  },
                  "request": {
                    "type": "integer"
                  }
                }
              }
            }
          }
        },
        "x-rustybin-permission": "mocks.read"
      }
    },
    "/_rustybin/mocks/{name}/operations/{op}": {
      "get": {
        "tags": [
          "Mocks"
        ],
        "summary": "Operation details",
        "operationId": "getMockOperation",
        "parameters": [
          {
            "name": "name",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Mock name"
          },
          {
            "name": "op",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "operationId"
          }
        ],
        "responses": {
          "200": {
            "description": "OK"
          },
          "404": {
            "description": "Unknown mock"
          },
          "403": {
            "description": "permission_required: the caller lacks mocks.read"
          }
        },
        "x-rustybin-permission": "mocks.read"
      },
      "put": {
        "tags": [
          "Mocks"
        ],
        "summary": "Set operation settings",
        "operationId": "setMockOperation",
        "parameters": [
          {
            "name": "name",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Mock name"
          },
          {
            "name": "op",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "operationId"
          }
        ],
        "responses": {
          "200": {
            "description": "OK"
          },
          "401": {
            "description": "Control-plane credentials required"
          },
          "403": {
            "description": "Admin token or admin scope required"
          },
          "404": {
            "description": "Unknown mock"
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object"
              }
            }
          }
        },
        "x-rustybin-permission": "mocks.write"
      }
    },
    "/_rustybin/mocks/{name}/operations/{op}/sample": {
      "get": {
        "tags": [
          "Mocks"
        ],
        "summary": "Generate a valid request and response",
        "operationId": "sampleMockOperation",
        "parameters": [
          {
            "name": "name",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Mock name"
          },
          {
            "name": "op",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "operationId"
          },
          {
            "name": "status",
            "in": "query",
            "schema": {
              "type": "integer"
            }
          },
          {
            "name": "mode",
            "in": "query",
            "schema": {
              "type": "string",
              "enum": [
                "examples",
                "generated",
                "static",
                "stateful"
              ]
            }
          },
          {
            "name": "example",
            "in": "query",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "seed",
            "in": "query",
            "schema": {
              "type": "integer"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK"
          },
          "404": {
            "description": "Unknown mock"
          },
          "403": {
            "description": "permission_required: the caller lacks mocks.read"
          }
        },
        "x-rustybin-permission": "mocks.read"
      }
    },
    "/_rustybin/mocks/{name}/operations/{op}/validate": {
      "post": {
        "tags": [
          "Mocks"
        ],
        "summary": "Validate a body",
        "operationId": "validateMockBody",
        "parameters": [
          {
            "name": "name",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Mock name"
          },
          {
            "name": "op",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "operationId"
          }
        ],
        "responses": {
          "200": {
            "description": "OK"
          },
          "404": {
            "description": "Unknown mock"
          },
          "403": {
            "description": "permission_required: the caller lacks mocks.read"
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "body"
                ],
                "properties": {
                  "kind": {
                    "type": "string",
                    "enum": [
                      "response",
                      "request"
                    ]
                  },
                  "status": {
                    "type": "integer"
                  },
                  "body": {}
                }
              }
            }
          }
        },
        "x-rustybin-permission": "mocks.read"
      }
    },
    "/_rustybin/mocks/{name}/requests": {
      "get": {
        "tags": [
          "Mocks"
        ],
        "summary": "Captured requests",
        "operationId": "listMockRequests",
        "parameters": [
          {
            "name": "name",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Mock name"
          },
          {
            "name": "limit",
            "in": "query",
            "schema": {
              "type": "integer"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK"
          },
          "404": {
            "description": "Unknown mock"
          },
          "403": {
            "description": "permission_required: the caller lacks traffic.read"
          }
        },
        "x-rustybin-permission": "traffic.read"
      },
      "delete": {
        "tags": [
          "Mocks"
        ],
        "summary": "Clear captured requests",
        "operationId": "clearMockRequests",
        "parameters": [
          {
            "name": "name",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Mock name"
          }
        ],
        "responses": {
          "200": {
            "description": "OK"
          },
          "401": {
            "description": "Control-plane credentials required"
          },
          "403": {
            "description": "Admin token or admin scope required"
          },
          "404": {
            "description": "Unknown mock"
          }
        },
        "x-rustybin-permission": "mocks.data"
      }
    },
    "/_rustybin/mocks/{name}/requests/stream": {
      "get": {
        "tags": [
          "Mocks"
        ],
        "summary": "Live feed of captured requests (SSE)",
        "operationId": "streamMockRequests",
        "parameters": [
          {
            "name": "name",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Mock name"
          }
        ],
        "responses": {
          "200": {
            "description": "text/event-stream of `request` events",
            "content": {
              "text/event-stream": {}
            }
          },
          "404": {
            "description": "Unknown mock"
          },
          "403": {
            "description": "permission_required: the caller lacks traffic.read"
          }
        },
        "x-rustybin-permission": "traffic.read"
      }
    },
    "/_rustybin/mocks/{name}/requests/{n}": {
      "get": {
        "tags": [
          "Mocks"
        ],
        "summary": "One captured request",
        "operationId": "getMockRequest",
        "parameters": [
          {
            "name": "name",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Mock name"
          },
          {
            "name": "n",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK"
          },
          "404": {
            "description": "Unknown mock"
          },
          "403": {
            "description": "permission_required: the caller lacks traffic.read"
          }
        },
        "x-rustybin-permission": "traffic.read"
      }
    },
    "/_rustybin/mocks/visit": {
      "get": {
        "tags": [
          "Mocks"
        ],
        "summary": "The caller's self-service visit",
        "operationId": "getMockVisit",
        "parameters": [
          {
            "name": "X-Rustybin-Mock-Token",
            "in": "header",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Manage token of the visit (self-service)"
          }
        ],
        "responses": {
          "200": {
            "description": "The visit"
          },
          "201": {
            "description": "Visit started: manage_token (shown once) and the visit"
          },
          "403": {
            "description": "rustybin_email_required: give an email address"
          },
          "404": {
            "description": "Self-service off, or no running visit for the token"
          },
          "409": {
            "description": "rustybin_extend_too_early"
          },
          "429": {
            "description": "rustybin_daily_limit or rustybin_visit_limit (Retry-After)"
          },
          "503": {
            "description": "rustybin_mocks_busy or rustybin_self_service_paused (Retry-After)"
          }
        },
        "x-rustybin-permission": "mocks.read"
      },
      "post": {
        "tags": [
          "Mocks"
        ],
        "summary": "Start a self-service visit",
        "operationId": "startMockVisit",
        "parameters": [
          {
            "name": "X-Rustybin-Mock-Token",
            "in": "header",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Manage token of the visit (self-service)"
          }
        ],
        "responses": {
          "200": {
            "description": "The visit"
          },
          "201": {
            "description": "Visit started: manage_token (shown once) and the visit"
          },
          "403": {
            "description": "rustybin_email_required: give an email address"
          },
          "404": {
            "description": "Self-service off, or no running visit for the token"
          },
          "409": {
            "description": "rustybin_extend_too_early"
          },
          "429": {
            "description": "rustybin_daily_limit or rustybin_visit_limit (Retry-After)"
          },
          "503": {
            "description": "rustybin_mocks_busy or rustybin_self_service_paused (Retry-After)"
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "email": {
                    "type": "string",
                    "format": "email"
                  },
                  "marketing_consent": {
                    "type": "boolean"
                  }
                }
              }
            }
          }
        },
        "x-rustybin-permission": "signed in"
      },
      "delete": {
        "tags": [
          "Mocks"
        ],
        "summary": "End the visit and delete its mocks",
        "operationId": "endMockVisit",
        "parameters": [
          {
            "name": "X-Rustybin-Mock-Token",
            "in": "header",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Manage token of the visit (self-service)"
          }
        ],
        "responses": {
          "200": {
            "description": "The visit"
          },
          "201": {
            "description": "Visit started: manage_token (shown once) and the visit"
          },
          "403": {
            "description": "rustybin_email_required: give an email address"
          },
          "404": {
            "description": "Self-service off, or no running visit for the token"
          },
          "409": {
            "description": "rustybin_extend_too_early"
          },
          "429": {
            "description": "rustybin_daily_limit or rustybin_visit_limit (Retry-After)"
          },
          "503": {
            "description": "rustybin_mocks_busy or rustybin_self_service_paused (Retry-After)"
          }
        },
        "x-rustybin-permission": "signed in"
      }
    },
    "/_rustybin/mocks/visit/extend": {
      "post": {
        "tags": [
          "Mocks"
        ],
        "summary": "One more period (optionally with the email step)",
        "operationId": "extendMockVisit",
        "parameters": [
          {
            "name": "X-Rustybin-Mock-Token",
            "in": "header",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Manage token of the visit (self-service)"
          }
        ],
        "responses": {
          "200": {
            "description": "The visit"
          },
          "201": {
            "description": "Visit started: manage_token (shown once) and the visit"
          },
          "403": {
            "description": "rustybin_email_required: give an email address"
          },
          "404": {
            "description": "Self-service off, or no running visit for the token"
          },
          "409": {
            "description": "rustybin_extend_too_early"
          },
          "429": {
            "description": "rustybin_daily_limit or rustybin_visit_limit (Retry-After)"
          },
          "503": {
            "description": "rustybin_mocks_busy or rustybin_self_service_paused (Retry-After)"
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "email": {
                    "type": "string",
                    "format": "email"
                  },
                  "marketing_consent": {
                    "type": "boolean"
                  }
                }
              }
            }
          }
        },
        "x-rustybin-permission": "signed in"
      }
    },
    "/_rustybin/mocks/visit/token": {
      "post": {
        "tags": [
          "Mocks"
        ],
        "summary": "Replace the manage token",
        "operationId": "rotateMockVisitToken",
        "parameters": [
          {
            "name": "X-Rustybin-Mock-Token",
            "in": "header",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Manage token of the visit (self-service)"
          }
        ],
        "responses": {
          "200": {
            "description": "The visit"
          },
          "201": {
            "description": "Visit started: manage_token (shown once) and the visit"
          },
          "403": {
            "description": "rustybin_email_required: give an email address"
          },
          "404": {
            "description": "Self-service off, or no running visit for the token"
          },
          "409": {
            "description": "rustybin_extend_too_early"
          },
          "429": {
            "description": "rustybin_daily_limit or rustybin_visit_limit (Retry-After)"
          },
          "503": {
            "description": "rustybin_mocks_busy or rustybin_self_service_paused (Retry-After)"
          }
        },
        "x-rustybin-permission": "signed in"
      }
    },
    "/_rustybin/mocks/visits": {
      "get": {
        "tags": [
          "Mocks"
        ],
        "summary": "Running visits (operators)",
        "operationId": "listMockVisits",
        "parameters": [],
        "responses": {
          "200": {
            "description": "OK"
          },
          "401": {
            "description": "Control-plane credentials required"
          },
          "403": {
            "description": "Admin token or admin scope required"
          },
          "404": {
            "description": "Unknown mock"
          }
        },
        "x-rustybin-permission": "visits.operate"
      },
      "delete": {
        "tags": [
          "Mocks"
        ],
        "summary": "End every visit (operators)",
        "operationId": "endAllMockVisits",
        "parameters": [],
        "responses": {
          "200": {
            "description": "OK"
          },
          "401": {
            "description": "Control-plane credentials required"
          },
          "403": {
            "description": "Admin token or admin scope required"
          },
          "404": {
            "description": "Unknown mock"
          }
        },
        "x-rustybin-permission": "visits.operate"
      }
    },
    "/_rustybin/mocks/visits/pause": {
      "post": {
        "tags": [
          "Mocks"
        ],
        "summary": "Stop new visits (operators)",
        "operationId": "pauseMockVisits",
        "parameters": [],
        "responses": {
          "200": {
            "description": "OK"
          },
          "401": {
            "description": "Control-plane credentials required"
          },
          "403": {
            "description": "Admin token or admin scope required"
          },
          "404": {
            "description": "Unknown mock"
          }
        },
        "x-rustybin-permission": "visits.operate"
      }
    },
    "/_rustybin/mocks/visits/resume": {
      "post": {
        "tags": [
          "Mocks"
        ],
        "summary": "Allow new visits (operators)",
        "operationId": "resumeMockVisits",
        "parameters": [],
        "responses": {
          "200": {
            "description": "OK"
          },
          "401": {
            "description": "Control-plane credentials required"
          },
          "403": {
            "description": "Admin token or admin scope required"
          },
          "404": {
            "description": "Unknown mock"
          }
        },
        "x-rustybin-permission": "visits.operate"
      }
    },
    "/_rustybin/mocks/visits/{id}": {
      "delete": {
        "tags": [
          "Mocks"
        ],
        "summary": "End one visit (operators)",
        "operationId": "endMockVisit",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Visit id from GET /_rustybin/mocks/visits"
          }
        ],
        "responses": {
          "200": {
            "description": "OK"
          },
          "401": {
            "description": "Control-plane credentials required"
          },
          "403": {
            "description": "Admin token or admin scope required"
          },
          "404": {
            "description": "Unknown mock"
          }
        },
        "x-rustybin-permission": "visits.operate"
      }
    },
    "/sse": {
      "get": {
        "tags": [
          "Streaming"
        ],
        "summary": "Numbered Server-Sent Events stream",
        "operationId": "sseStream",
        "parameters": [
          {
            "name": "count",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer"
            },
            "description": "Number of events (default 10)"
          },
          {
            "name": "interval_ms",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer"
            },
            "description": "Delay between events (default 1000)"
          },
          {
            "name": "event",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Event name"
          },
          {
            "name": "retry",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer"
            },
            "description": "Reconnection delay sent with the first event"
          },
          {
            "name": "mode",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "json (default) or text"
          },
          {
            "name": "heartbeat_ms",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer"
            },
            "description": "Comment heartbeat interval (default 15000, 0 disables)"
          },
          {
            "name": "last_event_id",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Resume after this id (Last-Event-ID header wins)"
          },
          {
            "name": "Last-Event-ID",
            "in": "header",
            "required": false,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "text/event-stream",
            "content": {
              "text/event-stream": {}
            }
          },
          "400": {
            "description": "Invalid parameters"
          }
        }
      }
    },
    "/sse/chat": {
      "get": {
        "tags": [
          "Streaming"
        ],
        "summary": "Streamed chat-style text",
        "operationId": "sseChat",
        "parameters": [
          {
            "name": "prompt",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Prompt echoed in the reply"
          },
          {
            "name": "max_tokens",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer"
            },
            "description": "Maximum number of word tokens"
          },
          {
            "name": "delay_ms",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer"
            },
            "description": "Delay between tokens (default 50)"
          }
        ],
        "responses": {
          "200": {
            "description": "text/event-stream",
            "content": {
              "text/event-stream": {}
            }
          },
          "400": {
            "description": "Invalid parameters"
          }
        }
      },
      "post": {
        "tags": [
          "Streaming"
        ],
        "summary": "Streamed chat-style text",
        "operationId": "sseChatPost",
        "requestBody": {
          "required": false,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "prompt": {
                    "type": "string"
                  },
                  "max_tokens": {
                    "type": "integer"
                  },
                  "delay_ms": {
                    "type": "integer"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "text/event-stream",
            "content": {
              "text/event-stream": {}
            }
          },
          "400": {
            "description": "Invalid parameters"
          }
        }
      }
    },
    "/webhooks": {
      "get": {
        "tags": [
          "Webhooks"
        ],
        "summary": "Webhook schemes and demo secrets",
        "operationId": "webhooksInfo",
        "responses": {
          "200": {
            "description": "Schemes and demo secrets"
          }
        }
      }
    },
    "/webhooks/verify": {
      "post": {
        "tags": [
          "Webhooks"
        ],
        "summary": "Verify a Standard Webhooks signature",
        "operationId": "verifyWebhook",
        "parameters": [
          {
            "name": "X-Webhook-Secret",
            "in": "header",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Signing secret (or ?secret=)"
          },
          {
            "name": "secret",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "tolerance",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "default": 300
            }
          },
          {
            "name": "ignore_timestamp",
            "in": "query",
            "required": false,
            "schema": {
              "type": "boolean"
            }
          },
          {
            "name": "webhook-id",
            "in": "header",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "webhook-timestamp",
            "in": "header",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "webhook-signature",
            "in": "header",
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "*/*": {
              "schema": {
                "type": "string"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Valid signature (report)"
          },
          "400": {
            "description": "Malformed input: missing_headers, missing_secret, invalid_secret, invalid_timestamp"
          },
          "401": {
            "description": "Invalid: signature_mismatch, timestamp_too_old, timestamp_too_new, no_supported_signature"
          }
        }
      }
    },
    "/webhooks/verify/{scheme}": {
      "post": {
        "tags": [
          "Webhooks"
        ],
        "summary": "Verify a webhook signature (standard, github, stripe)",
        "operationId": "verifyWebhookScheme",
        "parameters": [
          {
            "name": "scheme",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "enum": [
                "standard",
                "github",
                "stripe"
              ]
            }
          },
          {
            "name": "X-Webhook-Secret",
            "in": "header",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Signing secret (or ?secret=)"
          },
          {
            "name": "secret",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "tolerance",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "default": 300
            }
          },
          {
            "name": "ignore_timestamp",
            "in": "query",
            "required": false,
            "schema": {
              "type": "boolean"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "*/*": {
              "schema": {
                "type": "string"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Valid signature (report)"
          },
          "400": {
            "description": "Malformed input: missing_headers, missing_secret, invalid_secret, invalid_timestamp"
          },
          "401": {
            "description": "Invalid: signature_mismatch, timestamp_too_old, timestamp_too_new, no_supported_signature"
          }
        }
      }
    },
    "/webhooks/sign": {
      "get": {
        "tags": [
          "Webhooks"
        ],
        "summary": "Produce a signed example webhook",
        "operationId": "signWebhook",
        "parameters": [
          {
            "name": "scheme",
            "in": "query",
            "schema": {
              "type": "string",
              "enum": [
                "standard",
                "github",
                "stripe"
              ]
            }
          },
          {
            "name": "secret",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "payload",
            "in": "query",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "id",
            "in": "query",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "timestamp",
            "in": "query",
            "schema": {
              "type": "integer"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Headers, body, signed content and curl command"
          },
          "400": {
            "description": "Invalid secret or scheme"
          }
        }
      },
      "post": {
        "tags": [
          "Webhooks"
        ],
        "summary": "Sign the request body",
        "operationId": "signWebhookBody",
        "parameters": [
          {
            "name": "scheme",
            "in": "query",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "secret",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "id",
            "in": "query",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "timestamp",
            "in": "query",
            "schema": {
              "type": "integer"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "*/*": {
              "schema": {
                "type": "string"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Headers, body, signed content and curl command"
          },
          "400": {
            "description": "Invalid secret or scheme"
          }
        }
      }
    },
    "/webhooks/receive/{secret_id}": {
      "post": {
        "tags": [
          "Webhooks"
        ],
        "summary": "Receive a webhook signed with a demo secret",
        "operationId": "receiveWebhook",
        "parameters": [
          {
            "name": "secret_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "enum": [
                "demo",
                "github-docs"
              ]
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "*/*": {
              "schema": {
                "type": "string"
              }
            }
          }
        },
        "responses": {
          "204": {
            "description": "Valid"
          },
          "401": {
            "description": "Invalid or unsigned"
          },
          "404": {
            "description": "Unknown secret id"
          }
        }
      }
    },
    "/guardrails/azure/contentsafety/{operation}": {
      "post": {
        "tags": [
          "Guardrails"
        ],
        "summary": "Azure AI Content Safety style analysis",
        "description": "operation: text:analyze or text:shieldPrompt",
        "operationId": "guardrailsAzureContentSafety",
        "parameters": [
          {
            "name": "operation",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "enum": [
                "text:analyze",
                "text:shieldPrompt"
              ]
            }
          },
          {
            "name": "api-version",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "example": "2024-09-01"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "text": {
                    "type": "string"
                  },
                  "categories": {
                    "type": "array",
                    "items": {
                      "type": "string",
                      "enum": [
                        "Hate",
                        "SelfHarm",
                        "Sexual",
                        "Violence"
                      ]
                    }
                  },
                  "blocklistNames": {
                    "type": "array",
                    "items": {
                      "type": "string"
                    }
                  },
                  "haltOnBlocklistHit": {
                    "type": "boolean"
                  },
                  "outputType": {
                    "type": "string",
                    "enum": [
                      "FourSeverityLevels",
                      "EightSeverityLevels"
                    ]
                  },
                  "userPrompt": {
                    "type": "string"
                  },
                  "documents": {
                    "type": "array",
                    "items": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "categoriesAnalysis + blocklistsMatch, or userPromptAnalysis + documentsAnalysis"
          },
          "400": {
            "description": "InvalidRequestBody"
          },
          "404": {
            "description": "Unknown operation"
          }
        }
      }
    },
    "/guardrails/bedrock/guardrail/{id}/version/{version}/apply": {
      "post": {
        "tags": [
          "Guardrails"
        ],
        "summary": "AWS Bedrock ApplyGuardrail style assessment",
        "operationId": "guardrailsBedrockApply",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "version",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "source",
                  "content"
                ],
                "properties": {
                  "source": {
                    "type": "string",
                    "enum": [
                      "INPUT",
                      "OUTPUT"
                    ]
                  },
                  "outputScope": {
                    "type": "string",
                    "enum": [
                      "INTERVENTIONS",
                      "FULL"
                    ]
                  },
                  "content": {
                    "type": "array",
                    "items": {
                      "type": "object",
                      "properties": {
                        "text": {
                          "type": "object",
                          "properties": {
                            "text": {
                              "type": "string"
                            },
                            "qualifiers": {
                              "type": "array",
                              "items": {
                                "type": "string"
                              }
                            }
                          }
                        }
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "action (GUARDRAIL_INTERVENED or NONE), outputs, assessments, usage"
          },
          "400": {
            "description": "ValidationException"
          }
        }
      }
    },
    "/guardrails/check": {
      "post": {
        "tags": [
          "Guardrails"
        ],
        "summary": "Generic guardrail check",
        "operationId": "guardrailsCheck",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "text": {
                    "type": "string"
                  }
                }
              }
            },
            "text/plain": {
              "schema": {
                "type": "string"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "flagged, action, categories, prompt_injection, blocklist, pii, redacted_text"
          },
          "400": {
            "description": "Invalid body"
          }
        }
      }
    },
    "/guardrails/pii/redact": {
      "post": {
        "tags": [
          "Guardrails"
        ],
        "summary": "Redact PII",
        "operationId": "guardrailsPiiRedact",
        "parameters": [
          {
            "name": "mode",
            "in": "query",
            "schema": {
              "type": "string",
              "enum": [
                "label",
                "mask"
              ]
            }
          },
          {
            "name": "types",
            "in": "query",
            "schema": {
              "type": "string"
            },
            "description": "Comma separated PII types"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "text": {
                    "type": "string"
                  },
                  "mode": {
                    "type": "string",
                    "enum": [
                      "label",
                      "mask"
                    ]
                  },
                  "types": {
                    "type": "array",
                    "items": {
                      "type": "string",
                      "enum": [
                        "EMAIL",
                        "PHONE",
                        "SSN",
                        "CREDIT_CARD",
                        "IP_ADDRESS"
                      ]
                    }
                  }
                }
              }
            },
            "text/plain": {
              "schema": {
                "type": "string"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Redacted text (JSON report or text/plain)"
          },
          "400": {
            "description": "Invalid body, mode or type"
          }
        }
      }
    },
    "/gzip": {
      "get": {
        "tags": [
          "Response Shaping"
        ],
        "summary": "JSON echo compressed with Content-Encoding: gzip",
        "operationId": "gzip",
        "responses": {
          "200": {
            "description": "Compressed JSON with gzipped: true",
            "headers": {
              "Content-Encoding": {
                "schema": {
                  "type": "string",
                  "enum": [
                    "gzip"
                  ]
                }
              }
            },
            "content": {
              "application/json": {}
            }
          }
        }
      }
    },
    "/deflate": {
      "get": {
        "tags": [
          "Response Shaping"
        ],
        "summary": "JSON echo compressed with Content-Encoding: deflate",
        "operationId": "deflate",
        "responses": {
          "200": {
            "description": "Compressed JSON with deflated: true",
            "headers": {
              "Content-Encoding": {
                "schema": {
                  "type": "string",
                  "enum": [
                    "deflate"
                  ]
                }
              }
            },
            "content": {
              "application/json": {}
            }
          }
        }
      }
    },
    "/brotli": {
      "get": {
        "tags": [
          "Response Shaping"
        ],
        "summary": "JSON echo compressed with Content-Encoding: br",
        "operationId": "brotli",
        "responses": {
          "200": {
            "description": "Compressed JSON with brotli: true",
            "headers": {
              "Content-Encoding": {
                "schema": {
                  "type": "string",
                  "enum": [
                    "br"
                  ]
                }
              }
            },
            "content": {
              "application/json": {}
            }
          }
        }
      }
    },
    "/zstd": {
      "get": {
        "tags": [
          "Response Shaping"
        ],
        "summary": "JSON echo compressed with Content-Encoding: zstd",
        "operationId": "zstd",
        "responses": {
          "200": {
            "description": "Compressed JSON with zstd: true",
            "headers": {
              "Content-Encoding": {
                "schema": {
                  "type": "string",
                  "enum": [
                    "zstd"
                  ]
                }
              }
            },
            "content": {
              "application/json": {}
            }
          }
        }
      }
    },
    "/encoding/utf8": {
      "get": {
        "tags": [
          "Response Shaping"
        ],
        "summary": "UTF-8 sample page",
        "operationId": "encodingUtf8",
        "responses": {
          "200": {
            "description": "HTML",
            "content": {
              "text/html": {}
            }
          }
        }
      }
    },
    "/range/{n}": {
      "get": {
        "tags": [
          "Response Shaping"
        ],
        "summary": "n bytes with Range support",
        "operationId": "range",
        "parameters": [
          {
            "name": "n",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 102400
            }
          },
          {
            "name": "Range",
            "in": "header",
            "required": false,
            "schema": {
              "type": "string",
              "example": "bytes=0-99"
            }
          },
          {
            "name": "If-Range",
            "in": "header",
            "required": false,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Full body",
            "content": {
              "application/octet-stream": {}
            }
          },
          "206": {
            "description": "Partial content (Content-Range)"
          },
          "400": {
            "description": "n out of range"
          },
          "416": {
            "description": "Range not satisfiable (Content-Range: bytes */n)"
          }
        }
      }
    },
    "/bytes/{n}": {
      "get": {
        "tags": [
          "Response Shaping"
        ],
        "summary": "Random bytes",
        "operationId": "bytes",
        "parameters": [
          {
            "name": "n",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer",
              "minimum": 0
            },
            "description": "Number of bytes (capped)"
          },
          {
            "name": "seed",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Bytes",
            "content": {
              "application/octet-stream": {}
            }
          },
          "400": {
            "description": "Invalid n"
          }
        }
      }
    },
    "/stream/{n}": {
      "get": {
        "tags": [
          "Response Shaping"
        ],
        "summary": "Stream n JSON lines",
        "operationId": "streamLines",
        "parameters": [
          {
            "name": "n",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer",
              "minimum": 0
            },
            "description": "Number of lines (capped)"
          }
        ],
        "responses": {
          "200": {
            "description": "Newline delimited JSON",
            "content": {
              "application/json": {}
            }
          }
        }
      }
    },
    "/stream-bytes/{n}": {
      "get": {
        "tags": [
          "Response Shaping"
        ],
        "summary": "Stream random bytes",
        "operationId": "streamBytes",
        "parameters": [
          {
            "name": "n",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer",
              "minimum": 0
            },
            "description": "Number of bytes (capped)"
          },
          {
            "name": "seed",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer"
            }
          },
          {
            "name": "chunk_size",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "default": 10240
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Bytes",
            "content": {
              "application/octet-stream": {}
            }
          }
        }
      }
    },
    "/drip": {
      "get": {
        "tags": [
          "Response Shaping"
        ],
        "summary": "Drip bytes over time",
        "operationId": "drip",
        "parameters": [
          {
            "name": "duration",
            "in": "query",
            "schema": {
              "type": "number",
              "default": 2
            }
          },
          {
            "name": "numbytes",
            "in": "query",
            "schema": {
              "type": "integer",
              "default": 10
            }
          },
          {
            "name": "code",
            "in": "query",
            "schema": {
              "type": "integer",
              "default": 200
            }
          },
          {
            "name": "delay",
            "in": "query",
            "schema": {
              "type": "number",
              "default": 0
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Bytes",
            "content": {
              "application/octet-stream": {}
            }
          },
          "400": {
            "description": "Parameter out of range"
          }
        }
      }
    },
    "/links/{n}": {
      "get": {
        "tags": [
          "Response Shaping"
        ],
        "summary": "Redirect to the first links page",
        "operationId": "linksRoot",
        "parameters": [
          {
            "name": "n",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer",
              "minimum": 0
            },
            "description": "Number of links"
          }
        ],
        "responses": {
          "302": {
            "description": "Redirect to /links/{n}/0"
          }
        }
      }
    },
    "/links/{n}/{offset}": {
      "get": {
        "tags": [
          "Response Shaping"
        ],
        "summary": "HTML page of links",
        "operationId": "links",
        "parameters": [
          {
            "name": "n",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer",
              "minimum": 0
            },
            "description": "Number of links (max 200)"
          },
          {
            "name": "offset",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "HTML",
            "content": {
              "text/html": {}
            }
          }
        }
      }
    },
    "/base64/{value}": {
      "get": {
        "tags": [
          "Response Shaping"
        ],
        "summary": "Decode base64",
        "operationId": "base64Decode",
        "parameters": [
          {
            "name": "value",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Decoded text or bytes"
          },
          "400": {
            "description": "Invalid base64"
          }
        }
      }
    },
    "/redirect-to": {
      "get": {
        "tags": [
          "Redirects & Cookies"
        ],
        "summary": "Redirect to a relative or same-host URL",
        "operationId": "redirectTo",
        "parameters": [
          {
            "name": "url",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "status_code",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "default": 302
            }
          }
        ],
        "responses": {
          "302": {
            "description": "Redirect"
          },
          "400": {
            "description": "Target refused (external or malformed)"
          }
        }
      },
      "post": {
        "tags": [
          "Redirects & Cookies"
        ],
        "summary": "Redirect to a relative or same-host URL",
        "operationId": "redirectTo_post",
        "parameters": [
          {
            "name": "url",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "status_code",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "default": 302
            }
          }
        ],
        "responses": {
          "302": {
            "description": "Redirect"
          },
          "400": {
            "description": "Target refused (external or malformed)"
          }
        }
      },
      "put": {
        "tags": [
          "Redirects & Cookies"
        ],
        "summary": "Redirect to a relative or same-host URL",
        "operationId": "redirectTo_put",
        "parameters": [
          {
            "name": "url",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "status_code",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "default": 302
            }
          }
        ],
        "responses": {
          "302": {
            "description": "Redirect"
          },
          "400": {
            "description": "Target refused (external or malformed)"
          }
        }
      },
      "patch": {
        "tags": [
          "Redirects & Cookies"
        ],
        "summary": "Redirect to a relative or same-host URL",
        "operationId": "redirectTo_patch",
        "parameters": [
          {
            "name": "url",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "status_code",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "default": 302
            }
          }
        ],
        "responses": {
          "302": {
            "description": "Redirect"
          },
          "400": {
            "description": "Target refused (external or malformed)"
          }
        }
      },
      "delete": {
        "tags": [
          "Redirects & Cookies"
        ],
        "summary": "Redirect to a relative or same-host URL",
        "operationId": "redirectTo_delete",
        "parameters": [
          {
            "name": "url",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "status_code",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "default": 302
            }
          }
        ],
        "responses": {
          "302": {
            "description": "Redirect"
          },
          "400": {
            "description": "Target refused (external or malformed)"
          }
        }
      }
    },
    "/absolute-redirect/{n}": {
      "get": {
        "tags": [
          "Redirects & Cookies"
        ],
        "summary": "Absolute redirect chain",
        "operationId": "absoluteRedirect",
        "parameters": [
          {
            "name": "n",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer",
              "minimum": 0
            },
            "description": "Remaining redirects (1-10)"
          }
        ],
        "responses": {
          "302": {
            "description": "Redirect"
          },
          "400": {
            "description": "Invalid n or Host"
          }
        }
      }
    },
    "/jsonrpc": {
      "post": {
        "tags": [
          "Orchestration"
        ],
        "summary": "JSON-RPC 2.0 endpoint",
        "operationId": "jsonRpc",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "oneOf": [
                  {
                    "type": "object",
                    "required": [
                      "jsonrpc",
                      "method"
                    ],
                    "properties": {
                      "jsonrpc": {
                        "type": "string",
                        "enum": [
                          "2.0"
                        ]
                      },
                      "method": {
                        "type": "string",
                        "enum": [
                          "echo",
                          "add",
                          "subtract",
                          "sleep",
                          "error"
                        ]
                      },
                      "params": {
                        "oneOf": [
                          {
                            "type": "array",
                            "items": {}
                          },
                          {
                            "type": "object"
                          }
                        ]
                      },
                      "id": {
                        "oneOf": [
                          {
                            "type": "string"
                          },
                          {
                            "type": "number"
                          }
                        ],
                        "nullable": true
                      }
                    }
                  },
                  {
                    "type": "array",
                    "items": {
                      "type": "object",
                      "required": [
                        "jsonrpc",
                        "method"
                      ],
                      "properties": {
                        "jsonrpc": {
                          "type": "string",
                          "enum": [
                            "2.0"
                          ]
                        },
                        "method": {
                          "type": "string",
                          "enum": [
                            "echo",
                            "add",
                            "subtract",
                            "sleep",
                            "error"
                          ]
                        },
                        "params": {
                          "oneOf": [
                            {
                              "type": "array",
                              "items": {}
                            },
                            {
                              "type": "object"
                            }
                          ]
                        },
                        "id": {
                          "oneOf": [
                            {
                              "type": "string"
                            },
                            {
                              "type": "number"
                            }
                          ],
                          "nullable": true
                        }
                      }
                    }
                  }
                ]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Response object or array of response objects"
          },
          "204": {
            "description": "Only notifications were sent"
          }
        }
      }
    },
    "/auth/basic-auth": {
      "get": {
        "tags": [
          "Auth"
        ],
        "summary": "HTTP Basic authentication (default credentials)",
        "description": "Validates HTTP Basic auth with the default credentials basic:password.",
        "operationId": "getBasicAuth",
        "security": [
          {
            "basicAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "Authenticated",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AuthResponse"
                }
              },
              "application/xml": {
                "schema": {
                  "$ref": "#/components/schemas/AuthResponse"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "headers": {
              "WWW-Authenticate": {
                "schema": {
                  "type": "string",
                  "example": "Basic realm=\"rustybin\", charset=\"UTF-8\""
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AuthFailure"
                }
              },
              "application/xml": {
                "schema": {
                  "$ref": "#/components/schemas/AuthFailure"
                }
              }
            }
          }
        }
      },
      "post": {
        "tags": [
          "Auth"
        ],
        "summary": "HTTP Basic authentication (default credentials)",
        "description": "Validates HTTP Basic auth with the default credentials basic:password.",
        "operationId": "getBasicAuth_post",
        "security": [
          {
            "basicAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "Authenticated",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AuthResponse"
                }
              },
              "application/xml": {
                "schema": {
                  "$ref": "#/components/schemas/AuthResponse"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "headers": {
              "WWW-Authenticate": {
                "schema": {
                  "type": "string",
                  "example": "Basic realm=\"rustybin\", charset=\"UTF-8\""
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AuthFailure"
                }
              },
              "application/xml": {
                "schema": {
                  "$ref": "#/components/schemas/AuthFailure"
                }
              }
            }
          }
        }
      },
      "put": {
        "tags": [
          "Auth"
        ],
        "summary": "HTTP Basic authentication (default credentials)",
        "description": "Validates HTTP Basic auth with the default credentials basic:password.",
        "operationId": "getBasicAuth_put",
        "security": [
          {
            "basicAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "Authenticated",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AuthResponse"
                }
              },
              "application/xml": {
                "schema": {
                  "$ref": "#/components/schemas/AuthResponse"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "headers": {
              "WWW-Authenticate": {
                "schema": {
                  "type": "string",
                  "example": "Basic realm=\"rustybin\", charset=\"UTF-8\""
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AuthFailure"
                }
              },
              "application/xml": {
                "schema": {
                  "$ref": "#/components/schemas/AuthFailure"
                }
              }
            }
          }
        }
      },
      "patch": {
        "tags": [
          "Auth"
        ],
        "summary": "HTTP Basic authentication (default credentials)",
        "description": "Validates HTTP Basic auth with the default credentials basic:password.",
        "operationId": "getBasicAuth_patch",
        "security": [
          {
            "basicAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "Authenticated",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AuthResponse"
                }
              },
              "application/xml": {
                "schema": {
                  "$ref": "#/components/schemas/AuthResponse"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "headers": {
              "WWW-Authenticate": {
                "schema": {
                  "type": "string",
                  "example": "Basic realm=\"rustybin\", charset=\"UTF-8\""
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AuthFailure"
                }
              },
              "application/xml": {
                "schema": {
                  "$ref": "#/components/schemas/AuthFailure"
                }
              }
            }
          }
        }
      },
      "delete": {
        "tags": [
          "Auth"
        ],
        "summary": "HTTP Basic authentication (default credentials)",
        "description": "Validates HTTP Basic auth with the default credentials basic:password.",
        "operationId": "getBasicAuth_delete",
        "security": [
          {
            "basicAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "Authenticated",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AuthResponse"
                }
              },
              "application/xml": {
                "schema": {
                  "$ref": "#/components/schemas/AuthResponse"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "headers": {
              "WWW-Authenticate": {
                "schema": {
                  "type": "string",
                  "example": "Basic realm=\"rustybin\", charset=\"UTF-8\""
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AuthFailure"
                }
              },
              "application/xml": {
                "schema": {
                  "$ref": "#/components/schemas/AuthFailure"
                }
              }
            }
          }
        }
      }
    },
    "/auth/basic-auth/{username}/{password}": {
      "get": {
        "tags": [
          "Auth"
        ],
        "summary": "HTTP Basic authentication (custom credentials)",
        "description": "Validates HTTP Basic auth against the username and password given in the path.",
        "operationId": "getBasicAuthCustom",
        "security": [
          {
            "basicAuth": []
          }
        ],
        "parameters": [
          {
            "name": "username",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Expected username"
          },
          {
            "name": "password",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Expected password"
          }
        ],
        "responses": {
          "200": {
            "description": "Authenticated",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AuthResponse"
                }
              },
              "application/xml": {
                "schema": {
                  "$ref": "#/components/schemas/AuthResponse"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "headers": {
              "WWW-Authenticate": {
                "schema": {
                  "type": "string",
                  "example": "Basic realm=\"rustybin\", charset=\"UTF-8\""
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AuthFailure"
                }
              },
              "application/xml": {
                "schema": {
                  "$ref": "#/components/schemas/AuthFailure"
                }
              }
            }
          }
        }
      },
      "post": {
        "tags": [
          "Auth"
        ],
        "summary": "HTTP Basic authentication (custom credentials)",
        "description": "Validates HTTP Basic auth against the username and password given in the path.",
        "operationId": "getBasicAuthCustom_post",
        "security": [
          {
            "basicAuth": []
          }
        ],
        "parameters": [
          {
            "name": "username",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Expected username"
          },
          {
            "name": "password",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Expected password"
          }
        ],
        "responses": {
          "200": {
            "description": "Authenticated",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AuthResponse"
                }
              },
              "application/xml": {
                "schema": {
                  "$ref": "#/components/schemas/AuthResponse"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "headers": {
              "WWW-Authenticate": {
                "schema": {
                  "type": "string",
                  "example": "Basic realm=\"rustybin\", charset=\"UTF-8\""
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AuthFailure"
                }
              },
              "application/xml": {
                "schema": {
                  "$ref": "#/components/schemas/AuthFailure"
                }
              }
            }
          }
        }
      },
      "put": {
        "tags": [
          "Auth"
        ],
        "summary": "HTTP Basic authentication (custom credentials)",
        "description": "Validates HTTP Basic auth against the username and password given in the path.",
        "operationId": "getBasicAuthCustom_put",
        "security": [
          {
            "basicAuth": []
          }
        ],
        "parameters": [
          {
            "name": "username",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Expected username"
          },
          {
            "name": "password",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Expected password"
          }
        ],
        "responses": {
          "200": {
            "description": "Authenticated",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AuthResponse"
                }
              },
              "application/xml": {
                "schema": {
                  "$ref": "#/components/schemas/AuthResponse"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "headers": {
              "WWW-Authenticate": {
                "schema": {
                  "type": "string",
                  "example": "Basic realm=\"rustybin\", charset=\"UTF-8\""
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AuthFailure"
                }
              },
              "application/xml": {
                "schema": {
                  "$ref": "#/components/schemas/AuthFailure"
                }
              }
            }
          }
        }
      },
      "patch": {
        "tags": [
          "Auth"
        ],
        "summary": "HTTP Basic authentication (custom credentials)",
        "description": "Validates HTTP Basic auth against the username and password given in the path.",
        "operationId": "getBasicAuthCustom_patch",
        "security": [
          {
            "basicAuth": []
          }
        ],
        "parameters": [
          {
            "name": "username",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Expected username"
          },
          {
            "name": "password",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Expected password"
          }
        ],
        "responses": {
          "200": {
            "description": "Authenticated",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AuthResponse"
                }
              },
              "application/xml": {
                "schema": {
                  "$ref": "#/components/schemas/AuthResponse"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "headers": {
              "WWW-Authenticate": {
                "schema": {
                  "type": "string",
                  "example": "Basic realm=\"rustybin\", charset=\"UTF-8\""
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AuthFailure"
                }
              },
              "application/xml": {
                "schema": {
                  "$ref": "#/components/schemas/AuthFailure"
                }
              }
            }
          }
        }
      },
      "delete": {
        "tags": [
          "Auth"
        ],
        "summary": "HTTP Basic authentication (custom credentials)",
        "description": "Validates HTTP Basic auth against the username and password given in the path.",
        "operationId": "getBasicAuthCustom_delete",
        "security": [
          {
            "basicAuth": []
          }
        ],
        "parameters": [
          {
            "name": "username",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Expected username"
          },
          {
            "name": "password",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Expected password"
          }
        ],
        "responses": {
          "200": {
            "description": "Authenticated",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AuthResponse"
                }
              },
              "application/xml": {
                "schema": {
                  "$ref": "#/components/schemas/AuthResponse"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "headers": {
              "WWW-Authenticate": {
                "schema": {
                  "type": "string",
                  "example": "Basic realm=\"rustybin\", charset=\"UTF-8\""
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AuthFailure"
                }
              },
              "application/xml": {
                "schema": {
                  "$ref": "#/components/schemas/AuthFailure"
                }
              }
            }
          }
        }
      }
    },
    "/auth/api-key": {
      "get": {
        "tags": [
          "Auth"
        ],
        "summary": "API key authentication (default header)",
        "description": "Validates the API key in the `apikey` header against the default value `my-key`.",
        "operationId": "getApiKey",
        "security": [
          {
            "apiKeyAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "Authenticated",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AuthResponse"
                }
              },
              "application/xml": {
                "schema": {
                  "$ref": "#/components/schemas/AuthResponse"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AuthFailure"
                }
              },
              "application/xml": {
                "schema": {
                  "$ref": "#/components/schemas/AuthFailure"
                }
              }
            }
          }
        }
      },
      "post": {
        "tags": [
          "Auth"
        ],
        "summary": "API key authentication (default header)",
        "description": "Validates the API key in the `apikey` header against the default value `my-key`.",
        "operationId": "getApiKey_post",
        "security": [
          {
            "apiKeyAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "Authenticated",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AuthResponse"
                }
              },
              "application/xml": {
                "schema": {
                  "$ref": "#/components/schemas/AuthResponse"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AuthFailure"
                }
              },
              "application/xml": {
                "schema": {
                  "$ref": "#/components/schemas/AuthFailure"
                }
              }
            }
          }
        }
      },
      "put": {
        "tags": [
          "Auth"
        ],
        "summary": "API key authentication (default header)",
        "description": "Validates the API key in the `apikey` header against the default value `my-key`.",
        "operationId": "getApiKey_put",
        "security": [
          {
            "apiKeyAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "Authenticated",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AuthResponse"
                }
              },
              "application/xml": {
                "schema": {
                  "$ref": "#/components/schemas/AuthResponse"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AuthFailure"
                }
              },
              "application/xml": {
                "schema": {
                  "$ref": "#/components/schemas/AuthFailure"
                }
              }
            }
          }
        }
      },
      "patch": {
        "tags": [
          "Auth"
        ],
        "summary": "API key authentication (default header)",
        "description": "Validates the API key in the `apikey` header against the default value `my-key`.",
        "operationId": "getApiKey_patch",
        "security": [
          {
            "apiKeyAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "Authenticated",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AuthResponse"
                }
              },
              "application/xml": {
                "schema": {
                  "$ref": "#/components/schemas/AuthResponse"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AuthFailure"
                }
              },
              "application/xml": {
                "schema": {
                  "$ref": "#/components/schemas/AuthFailure"
                }
              }
            }
          }
        }
      },
      "delete": {
        "tags": [
          "Auth"
        ],
        "summary": "API key authentication (default header)",
        "description": "Validates the API key in the `apikey` header against the default value `my-key`.",
        "operationId": "getApiKey_delete",
        "security": [
          {
            "apiKeyAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "Authenticated",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AuthResponse"
                }
              },
              "application/xml": {
                "schema": {
                  "$ref": "#/components/schemas/AuthResponse"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AuthFailure"
                }
              },
              "application/xml": {
                "schema": {
                  "$ref": "#/components/schemas/AuthFailure"
                }
              }
            }
          }
        }
      }
    },
    "/auth/api-key/{header_name}/{key_value}": {
      "get": {
        "tags": [
          "Auth"
        ],
        "summary": "API key authentication (custom header and value)",
        "description": "Validates the API key in a custom header against a custom value, both from the path.",
        "operationId": "getApiKeyCustom",
        "parameters": [
          {
            "name": "header_name",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Header name to check"
          },
          {
            "name": "key_value",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Expected key value"
          }
        ],
        "responses": {
          "200": {
            "description": "Authenticated",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AuthResponse"
                }
              },
              "application/xml": {
                "schema": {
                  "$ref": "#/components/schemas/AuthResponse"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AuthFailure"
                }
              },
              "application/xml": {
                "schema": {
                  "$ref": "#/components/schemas/AuthFailure"
                }
              }
            }
          }
        }
      },
      "post": {
        "tags": [
          "Auth"
        ],
        "summary": "API key authentication (custom header and value)",
        "description": "Validates the API key in a custom header against a custom value, both from the path.",
        "operationId": "getApiKeyCustom_post",
        "parameters": [
          {
            "name": "header_name",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Header name to check"
          },
          {
            "name": "key_value",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Expected key value"
          }
        ],
        "responses": {
          "200": {
            "description": "Authenticated",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AuthResponse"
                }
              },
              "application/xml": {
                "schema": {
                  "$ref": "#/components/schemas/AuthResponse"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AuthFailure"
                }
              },
              "application/xml": {
                "schema": {
                  "$ref": "#/components/schemas/AuthFailure"
                }
              }
            }
          }
        }
      },
      "put": {
        "tags": [
          "Auth"
        ],
        "summary": "API key authentication (custom header and value)",
        "description": "Validates the API key in a custom header against a custom value, both from the path.",
        "operationId": "getApiKeyCustom_put",
        "parameters": [
          {
            "name": "header_name",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Header name to check"
          },
          {
            "name": "key_value",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Expected key value"
          }
        ],
        "responses": {
          "200": {
            "description": "Authenticated",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AuthResponse"
                }
              },
              "application/xml": {
                "schema": {
                  "$ref": "#/components/schemas/AuthResponse"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AuthFailure"
                }
              },
              "application/xml": {
                "schema": {
                  "$ref": "#/components/schemas/AuthFailure"
                }
              }
            }
          }
        }
      },
      "patch": {
        "tags": [
          "Auth"
        ],
        "summary": "API key authentication (custom header and value)",
        "description": "Validates the API key in a custom header against a custom value, both from the path.",
        "operationId": "getApiKeyCustom_patch",
        "parameters": [
          {
            "name": "header_name",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Header name to check"
          },
          {
            "name": "key_value",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Expected key value"
          }
        ],
        "responses": {
          "200": {
            "description": "Authenticated",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AuthResponse"
                }
              },
              "application/xml": {
                "schema": {
                  "$ref": "#/components/schemas/AuthResponse"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AuthFailure"
                }
              },
              "application/xml": {
                "schema": {
                  "$ref": "#/components/schemas/AuthFailure"
                }
              }
            }
          }
        }
      },
      "delete": {
        "tags": [
          "Auth"
        ],
        "summary": "API key authentication (custom header and value)",
        "description": "Validates the API key in a custom header against a custom value, both from the path.",
        "operationId": "getApiKeyCustom_delete",
        "parameters": [
          {
            "name": "header_name",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Header name to check"
          },
          {
            "name": "key_value",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Expected key value"
          }
        ],
        "responses": {
          "200": {
            "description": "Authenticated",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AuthResponse"
                }
              },
              "application/xml": {
                "schema": {
                  "$ref": "#/components/schemas/AuthResponse"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AuthFailure"
                }
              },
              "application/xml": {
                "schema": {
                  "$ref": "#/components/schemas/AuthFailure"
                }
              }
            }
          }
        }
      }
    },
    "/auth/hmac": {
      "get": {
        "tags": [
          "Auth"
        ],
        "summary": "HMAC authentication (default credentials alice / secret)",
        "description": "Validates `Authorization` or `Proxy-Authorization: hmac username=\"...\", algorithm=\"hmac-sha256\", headers=\"date request-line\", signature=\"...\"` (or draft-cavage `Signature keyId=...`). The signature is base64(HMAC(secret, signing string)); the signing string has one `name: value` line per listed header (default `date`; repeated headers joined with \", \"), plus the pseudo headers `request-line` and `(request-target)`. Date or X-Date is required and checked against the clock skew. When `digest` is signed, `Digest: SHA-256=<base64>` must match the body. Supports hmac-sha1/sha256/sha384/sha512. Default credentials: alice / secret.",
        "operationId": "authHmac",
        "parameters": [
          {
            "name": "clock_skew",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "minimum": 0,
              "maximum": 604800,
              "default": 300
            },
            "description": "Allowed difference in seconds between Date / X-Date and now (0 disables the check)"
          }
        ],
        "responses": {
          "200": {
            "description": "Signature valid",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AuthResponse"
                }
              },
              "application/xml": {
                "schema": {
                  "$ref": "#/components/schemas/AuthResponse"
                }
              }
            }
          },
          "400": {
            "description": "Invalid clock_skew",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AuthFailure"
                }
              },
              "application/xml": {
                "schema": {
                  "$ref": "#/components/schemas/AuthFailure"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid signature, date outside the clock skew, or digest mismatch",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AuthFailure"
                }
              },
              "application/xml": {
                "schema": {
                  "$ref": "#/components/schemas/AuthFailure"
                }
              }
            }
          }
        }
      },
      "post": {
        "tags": [
          "Auth"
        ],
        "summary": "HMAC authentication (default credentials alice / secret)",
        "description": "Validates `Authorization` or `Proxy-Authorization: hmac username=\"...\", algorithm=\"hmac-sha256\", headers=\"date request-line\", signature=\"...\"` (or draft-cavage `Signature keyId=...`). The signature is base64(HMAC(secret, signing string)); the signing string has one `name: value` line per listed header (default `date`; repeated headers joined with \", \"), plus the pseudo headers `request-line` and `(request-target)`. Date or X-Date is required and checked against the clock skew. When `digest` is signed, `Digest: SHA-256=<base64>` must match the body. Supports hmac-sha1/sha256/sha384/sha512. Default credentials: alice / secret.",
        "operationId": "authHmac_post",
        "parameters": [
          {
            "name": "clock_skew",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "minimum": 0,
              "maximum": 604800,
              "default": 300
            },
            "description": "Allowed difference in seconds between Date / X-Date and now (0 disables the check)"
          }
        ],
        "responses": {
          "200": {
            "description": "Signature valid",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AuthResponse"
                }
              },
              "application/xml": {
                "schema": {
                  "$ref": "#/components/schemas/AuthResponse"
                }
              }
            }
          },
          "400": {
            "description": "Invalid clock_skew",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AuthFailure"
                }
              },
              "application/xml": {
                "schema": {
                  "$ref": "#/components/schemas/AuthFailure"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid signature, date outside the clock skew, or digest mismatch",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AuthFailure"
                }
              },
              "application/xml": {
                "schema": {
                  "$ref": "#/components/schemas/AuthFailure"
                }
              }
            }
          }
        }
      },
      "put": {
        "tags": [
          "Auth"
        ],
        "summary": "HMAC authentication (default credentials alice / secret)",
        "description": "Validates `Authorization` or `Proxy-Authorization: hmac username=\"...\", algorithm=\"hmac-sha256\", headers=\"date request-line\", signature=\"...\"` (or draft-cavage `Signature keyId=...`). The signature is base64(HMAC(secret, signing string)); the signing string has one `name: value` line per listed header (default `date`; repeated headers joined with \", \"), plus the pseudo headers `request-line` and `(request-target)`. Date or X-Date is required and checked against the clock skew. When `digest` is signed, `Digest: SHA-256=<base64>` must match the body. Supports hmac-sha1/sha256/sha384/sha512. Default credentials: alice / secret.",
        "operationId": "authHmac_put",
        "parameters": [
          {
            "name": "clock_skew",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "minimum": 0,
              "maximum": 604800,
              "default": 300
            },
            "description": "Allowed difference in seconds between Date / X-Date and now (0 disables the check)"
          }
        ],
        "responses": {
          "200": {
            "description": "Signature valid",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AuthResponse"
                }
              },
              "application/xml": {
                "schema": {
                  "$ref": "#/components/schemas/AuthResponse"
                }
              }
            }
          },
          "400": {
            "description": "Invalid clock_skew",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AuthFailure"
                }
              },
              "application/xml": {
                "schema": {
                  "$ref": "#/components/schemas/AuthFailure"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid signature, date outside the clock skew, or digest mismatch",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AuthFailure"
                }
              },
              "application/xml": {
                "schema": {
                  "$ref": "#/components/schemas/AuthFailure"
                }
              }
            }
          }
        }
      },
      "patch": {
        "tags": [
          "Auth"
        ],
        "summary": "HMAC authentication (default credentials alice / secret)",
        "description": "Validates `Authorization` or `Proxy-Authorization: hmac username=\"...\", algorithm=\"hmac-sha256\", headers=\"date request-line\", signature=\"...\"` (or draft-cavage `Signature keyId=...`). The signature is base64(HMAC(secret, signing string)); the signing string has one `name: value` line per listed header (default `date`; repeated headers joined with \", \"), plus the pseudo headers `request-line` and `(request-target)`. Date or X-Date is required and checked against the clock skew. When `digest` is signed, `Digest: SHA-256=<base64>` must match the body. Supports hmac-sha1/sha256/sha384/sha512. Default credentials: alice / secret.",
        "operationId": "authHmac_patch",
        "parameters": [
          {
            "name": "clock_skew",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "minimum": 0,
              "maximum": 604800,
              "default": 300
            },
            "description": "Allowed difference in seconds between Date / X-Date and now (0 disables the check)"
          }
        ],
        "responses": {
          "200": {
            "description": "Signature valid",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AuthResponse"
                }
              },
              "application/xml": {
                "schema": {
                  "$ref": "#/components/schemas/AuthResponse"
                }
              }
            }
          },
          "400": {
            "description": "Invalid clock_skew",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AuthFailure"
                }
              },
              "application/xml": {
                "schema": {
                  "$ref": "#/components/schemas/AuthFailure"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid signature, date outside the clock skew, or digest mismatch",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AuthFailure"
                }
              },
              "application/xml": {
                "schema": {
                  "$ref": "#/components/schemas/AuthFailure"
                }
              }
            }
          }
        }
      },
      "delete": {
        "tags": [
          "Auth"
        ],
        "summary": "HMAC authentication (default credentials alice / secret)",
        "description": "Validates `Authorization` or `Proxy-Authorization: hmac username=\"...\", algorithm=\"hmac-sha256\", headers=\"date request-line\", signature=\"...\"` (or draft-cavage `Signature keyId=...`). The signature is base64(HMAC(secret, signing string)); the signing string has one `name: value` line per listed header (default `date`; repeated headers joined with \", \"), plus the pseudo headers `request-line` and `(request-target)`. Date or X-Date is required and checked against the clock skew. When `digest` is signed, `Digest: SHA-256=<base64>` must match the body. Supports hmac-sha1/sha256/sha384/sha512. Default credentials: alice / secret.",
        "operationId": "authHmac_delete",
        "parameters": [
          {
            "name": "clock_skew",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "minimum": 0,
              "maximum": 604800,
              "default": 300
            },
            "description": "Allowed difference in seconds between Date / X-Date and now (0 disables the check)"
          }
        ],
        "responses": {
          "200": {
            "description": "Signature valid",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AuthResponse"
                }
              },
              "application/xml": {
                "schema": {
                  "$ref": "#/components/schemas/AuthResponse"
                }
              }
            }
          },
          "400": {
            "description": "Invalid clock_skew",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AuthFailure"
                }
              },
              "application/xml": {
                "schema": {
                  "$ref": "#/components/schemas/AuthFailure"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid signature, date outside the clock skew, or digest mismatch",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AuthFailure"
                }
              },
              "application/xml": {
                "schema": {
                  "$ref": "#/components/schemas/AuthFailure"
                }
              }
            }
          }
        }
      }
    },
    "/auth/hmac/{username}/{secret}": {
      "get": {
        "tags": [
          "Auth"
        ],
        "summary": "HMAC authentication (custom credentials)",
        "description": "Same as /auth/hmac but validates against the username and secret supplied in the path.",
        "operationId": "authHmacCustom",
        "parameters": [
          {
            "name": "username",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "secret",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "clock_skew",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "minimum": 0,
              "maximum": 604800,
              "default": 300
            },
            "description": "Allowed difference in seconds between Date / X-Date and now (0 disables the check)"
          }
        ],
        "responses": {
          "200": {
            "description": "Signature valid",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AuthResponse"
                }
              },
              "application/xml": {
                "schema": {
                  "$ref": "#/components/schemas/AuthResponse"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid signature",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AuthFailure"
                }
              },
              "application/xml": {
                "schema": {
                  "$ref": "#/components/schemas/AuthFailure"
                }
              }
            }
          }
        }
      },
      "post": {
        "tags": [
          "Auth"
        ],
        "summary": "HMAC authentication (custom credentials)",
        "description": "Same as /auth/hmac but validates against the username and secret supplied in the path.",
        "operationId": "authHmacCustom_post",
        "parameters": [
          {
            "name": "username",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "secret",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "clock_skew",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "minimum": 0,
              "maximum": 604800,
              "default": 300
            },
            "description": "Allowed difference in seconds between Date / X-Date and now (0 disables the check)"
          }
        ],
        "responses": {
          "200": {
            "description": "Signature valid",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AuthResponse"
                }
              },
              "application/xml": {
                "schema": {
                  "$ref": "#/components/schemas/AuthResponse"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid signature",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AuthFailure"
                }
              },
              "application/xml": {
                "schema": {
                  "$ref": "#/components/schemas/AuthFailure"
                }
              }
            }
          }
        }
      },
      "put": {
        "tags": [
          "Auth"
        ],
        "summary": "HMAC authentication (custom credentials)",
        "description": "Same as /auth/hmac but validates against the username and secret supplied in the path.",
        "operationId": "authHmacCustom_put",
        "parameters": [
          {
            "name": "username",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "secret",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "clock_skew",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "minimum": 0,
              "maximum": 604800,
              "default": 300
            },
            "description": "Allowed difference in seconds between Date / X-Date and now (0 disables the check)"
          }
        ],
        "responses": {
          "200": {
            "description": "Signature valid",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AuthResponse"
                }
              },
              "application/xml": {
                "schema": {
                  "$ref": "#/components/schemas/AuthResponse"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid signature",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AuthFailure"
                }
              },
              "application/xml": {
                "schema": {
                  "$ref": "#/components/schemas/AuthFailure"
                }
              }
            }
          }
        }
      },
      "patch": {
        "tags": [
          "Auth"
        ],
        "summary": "HMAC authentication (custom credentials)",
        "description": "Same as /auth/hmac but validates against the username and secret supplied in the path.",
        "operationId": "authHmacCustom_patch",
        "parameters": [
          {
            "name": "username",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "secret",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "clock_skew",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "minimum": 0,
              "maximum": 604800,
              "default": 300
            },
            "description": "Allowed difference in seconds between Date / X-Date and now (0 disables the check)"
          }
        ],
        "responses": {
          "200": {
            "description": "Signature valid",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AuthResponse"
                }
              },
              "application/xml": {
                "schema": {
                  "$ref": "#/components/schemas/AuthResponse"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid signature",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AuthFailure"
                }
              },
              "application/xml": {
                "schema": {
                  "$ref": "#/components/schemas/AuthFailure"
                }
              }
            }
          }
        }
      },
      "delete": {
        "tags": [
          "Auth"
        ],
        "summary": "HMAC authentication (custom credentials)",
        "description": "Same as /auth/hmac but validates against the username and secret supplied in the path.",
        "operationId": "authHmacCustom_delete",
        "parameters": [
          {
            "name": "username",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "secret",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "clock_skew",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "minimum": 0,
              "maximum": 604800,
              "default": 300
            },
            "description": "Allowed difference in seconds between Date / X-Date and now (0 disables the check)"
          }
        ],
        "responses": {
          "200": {
            "description": "Signature valid",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AuthResponse"
                }
              },
              "application/xml": {
                "schema": {
                  "$ref": "#/components/schemas/AuthResponse"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid signature",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AuthFailure"
                }
              },
              "application/xml": {
                "schema": {
                  "$ref": "#/components/schemas/AuthFailure"
                }
              }
            }
          }
        }
      }
    },
    "/auth/jwt": {
      "get": {
        "tags": [
          "Auth"
        ],
        "summary": "JWT validation",
        "description": "Verifies the Bearer JWT: HS256 with the demo secret or RS256 with the IdP key (selected by the header alg; none and other algorithms are rejected), exp (required), nbf, and the optional iss / aud query constraints.",
        "operationId": "getJwt",
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "parameters": [
          {
            "name": "iss",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Required issuer"
          },
          {
            "name": "aud",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Required audience"
          }
        ],
        "responses": {
          "200": {
            "description": "Token valid",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AuthResponse"
                }
              },
              "application/xml": {
                "schema": {
                  "$ref": "#/components/schemas/AuthResponse"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid token (WWW-Authenticate: Bearer error=\"invalid_token\")",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AuthFailure"
                }
              },
              "application/xml": {
                "schema": {
                  "$ref": "#/components/schemas/AuthFailure"
                }
              }
            }
          }
        }
      },
      "post": {
        "tags": [
          "Auth"
        ],
        "summary": "JWT validation",
        "description": "Verifies the Bearer JWT: HS256 with the demo secret or RS256 with the IdP key (selected by the header alg; none and other algorithms are rejected), exp (required), nbf, and the optional iss / aud query constraints.",
        "operationId": "getJwt_post",
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "parameters": [
          {
            "name": "iss",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Required issuer"
          },
          {
            "name": "aud",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Required audience"
          }
        ],
        "responses": {
          "200": {
            "description": "Token valid",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AuthResponse"
                }
              },
              "application/xml": {
                "schema": {
                  "$ref": "#/components/schemas/AuthResponse"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid token (WWW-Authenticate: Bearer error=\"invalid_token\")",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AuthFailure"
                }
              },
              "application/xml": {
                "schema": {
                  "$ref": "#/components/schemas/AuthFailure"
                }
              }
            }
          }
        }
      },
      "put": {
        "tags": [
          "Auth"
        ],
        "summary": "JWT validation",
        "description": "Verifies the Bearer JWT: HS256 with the demo secret or RS256 with the IdP key (selected by the header alg; none and other algorithms are rejected), exp (required), nbf, and the optional iss / aud query constraints.",
        "operationId": "getJwt_put",
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "parameters": [
          {
            "name": "iss",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Required issuer"
          },
          {
            "name": "aud",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Required audience"
          }
        ],
        "responses": {
          "200": {
            "description": "Token valid",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AuthResponse"
                }
              },
              "application/xml": {
                "schema": {
                  "$ref": "#/components/schemas/AuthResponse"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid token (WWW-Authenticate: Bearer error=\"invalid_token\")",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AuthFailure"
                }
              },
              "application/xml": {
                "schema": {
                  "$ref": "#/components/schemas/AuthFailure"
                }
              }
            }
          }
        }
      },
      "patch": {
        "tags": [
          "Auth"
        ],
        "summary": "JWT validation",
        "description": "Verifies the Bearer JWT: HS256 with the demo secret or RS256 with the IdP key (selected by the header alg; none and other algorithms are rejected), exp (required), nbf, and the optional iss / aud query constraints.",
        "operationId": "getJwt_patch",
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "parameters": [
          {
            "name": "iss",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Required issuer"
          },
          {
            "name": "aud",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Required audience"
          }
        ],
        "responses": {
          "200": {
            "description": "Token valid",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AuthResponse"
                }
              },
              "application/xml": {
                "schema": {
                  "$ref": "#/components/schemas/AuthResponse"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid token (WWW-Authenticate: Bearer error=\"invalid_token\")",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AuthFailure"
                }
              },
              "application/xml": {
                "schema": {
                  "$ref": "#/components/schemas/AuthFailure"
                }
              }
            }
          }
        }
      },
      "delete": {
        "tags": [
          "Auth"
        ],
        "summary": "JWT validation",
        "description": "Verifies the Bearer JWT: HS256 with the demo secret or RS256 with the IdP key (selected by the header alg; none and other algorithms are rejected), exp (required), nbf, and the optional iss / aud query constraints.",
        "operationId": "getJwt_delete",
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "parameters": [
          {
            "name": "iss",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Required issuer"
          },
          {
            "name": "aud",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Required audience"
          }
        ],
        "responses": {
          "200": {
            "description": "Token valid",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AuthResponse"
                }
              },
              "application/xml": {
                "schema": {
                  "$ref": "#/components/schemas/AuthResponse"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid token (WWW-Authenticate: Bearer error=\"invalid_token\")",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AuthFailure"
                }
              },
              "application/xml": {
                "schema": {
                  "$ref": "#/components/schemas/AuthFailure"
                }
              }
            }
          }
        }
      }
    },
    "/auth/jwt/decode": {
      "get": {
        "tags": [
          "Auth"
        ],
        "summary": "JWT decode (no validation)",
        "description": "Returns the header and claims of the Bearer JWT WITHOUT verifying signature or claims.",
        "operationId": "getJwtDecode",
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "Decoded token",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "verified": {
                      "type": "boolean",
                      "example": false
                    },
                    "jwt_header": {
                      "type": "object"
                    },
                    "claims": {
                      "type": "object"
                    },
                    "expired": {
                      "type": "boolean"
                    },
                    "note": {
                      "type": "string"
                    }
                  }
                }
              },
              "application/xml": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "verified": {
                      "type": "boolean",
                      "example": false
                    },
                    "jwt_header": {
                      "type": "object"
                    },
                    "claims": {
                      "type": "object"
                    },
                    "expired": {
                      "type": "boolean"
                    },
                    "note": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Malformed token",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AuthFailure"
                }
              },
              "application/xml": {
                "schema": {
                  "$ref": "#/components/schemas/AuthFailure"
                }
              }
            }
          },
          "401": {
            "description": "Missing Bearer token",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AuthFailure"
                }
              },
              "application/xml": {
                "schema": {
                  "$ref": "#/components/schemas/AuthFailure"
                }
              }
            }
          }
        }
      },
      "post": {
        "tags": [
          "Auth"
        ],
        "summary": "JWT decode (no validation)",
        "description": "Returns the header and claims of the Bearer JWT WITHOUT verifying signature or claims.",
        "operationId": "getJwtDecode_post",
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "Decoded token",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "verified": {
                      "type": "boolean",
                      "example": false
                    },
                    "jwt_header": {
                      "type": "object"
                    },
                    "claims": {
                      "type": "object"
                    },
                    "expired": {
                      "type": "boolean"
                    },
                    "note": {
                      "type": "string"
                    }
                  }
                }
              },
              "application/xml": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "verified": {
                      "type": "boolean",
                      "example": false
                    },
                    "jwt_header": {
                      "type": "object"
                    },
                    "claims": {
                      "type": "object"
                    },
                    "expired": {
                      "type": "boolean"
                    },
                    "note": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Malformed token",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AuthFailure"
                }
              },
              "application/xml": {
                "schema": {
                  "$ref": "#/components/schemas/AuthFailure"
                }
              }
            }
          },
          "401": {
            "description": "Missing Bearer token",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AuthFailure"
                }
              },
              "application/xml": {
                "schema": {
                  "$ref": "#/components/schemas/AuthFailure"
                }
              }
            }
          }
        }
      },
      "put": {
        "tags": [
          "Auth"
        ],
        "summary": "JWT decode (no validation)",
        "description": "Returns the header and claims of the Bearer JWT WITHOUT verifying signature or claims.",
        "operationId": "getJwtDecode_put",
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "Decoded token",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "verified": {
                      "type": "boolean",
                      "example": false
                    },
                    "jwt_header": {
                      "type": "object"
                    },
                    "claims": {
                      "type": "object"
                    },
                    "expired": {
                      "type": "boolean"
                    },
                    "note": {
                      "type": "string"
                    }
                  }
                }
              },
              "application/xml": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "verified": {
                      "type": "boolean",
                      "example": false
                    },
                    "jwt_header": {
                      "type": "object"
                    },
                    "claims": {
                      "type": "object"
                    },
                    "expired": {
                      "type": "boolean"
                    },
                    "note": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Malformed token",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AuthFailure"
                }
              },
              "application/xml": {
                "schema": {
                  "$ref": "#/components/schemas/AuthFailure"
                }
              }
            }
          },
          "401": {
            "description": "Missing Bearer token",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AuthFailure"
                }
              },
              "application/xml": {
                "schema": {
                  "$ref": "#/components/schemas/AuthFailure"
                }
              }
            }
          }
        }
      },
      "patch": {
        "tags": [
          "Auth"
        ],
        "summary": "JWT decode (no validation)",
        "description": "Returns the header and claims of the Bearer JWT WITHOUT verifying signature or claims.",
        "operationId": "getJwtDecode_patch",
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "Decoded token",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "verified": {
                      "type": "boolean",
                      "example": false
                    },
                    "jwt_header": {
                      "type": "object"
                    },
                    "claims": {
                      "type": "object"
                    },
                    "expired": {
                      "type": "boolean"
                    },
                    "note": {
                      "type": "string"
                    }
                  }
                }
              },
              "application/xml": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "verified": {
                      "type": "boolean",
                      "example": false
                    },
                    "jwt_header": {
                      "type": "object"
                    },
                    "claims": {
                      "type": "object"
                    },
                    "expired": {
                      "type": "boolean"
                    },
                    "note": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Malformed token",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AuthFailure"
                }
              },
              "application/xml": {
                "schema": {
                  "$ref": "#/components/schemas/AuthFailure"
                }
              }
            }
          },
          "401": {
            "description": "Missing Bearer token",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AuthFailure"
                }
              },
              "application/xml": {
                "schema": {
                  "$ref": "#/components/schemas/AuthFailure"
                }
              }
            }
          }
        }
      },
      "delete": {
        "tags": [
          "Auth"
        ],
        "summary": "JWT decode (no validation)",
        "description": "Returns the header and claims of the Bearer JWT WITHOUT verifying signature or claims.",
        "operationId": "getJwtDecode_delete",
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "Decoded token",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "verified": {
                      "type": "boolean",
                      "example": false
                    },
                    "jwt_header": {
                      "type": "object"
                    },
                    "claims": {
                      "type": "object"
                    },
                    "expired": {
                      "type": "boolean"
                    },
                    "note": {
                      "type": "string"
                    }
                  }
                }
              },
              "application/xml": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "verified": {
                      "type": "boolean",
                      "example": false
                    },
                    "jwt_header": {
                      "type": "object"
                    },
                    "claims": {
                      "type": "object"
                    },
                    "expired": {
                      "type": "boolean"
                    },
                    "note": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Malformed token",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AuthFailure"
                }
              },
              "application/xml": {
                "schema": {
                  "$ref": "#/components/schemas/AuthFailure"
                }
              }
            }
          },
          "401": {
            "description": "Missing Bearer token",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AuthFailure"
                }
              },
              "application/xml": {
                "schema": {
                  "$ref": "#/components/schemas/AuthFailure"
                }
              }
            }
          }
        }
      }
    },
    "/auth/jwt/exchange": {
      "post": {
        "tags": [
          "Auth"
        ],
        "summary": "JWT token exchange",
        "description": "Validates the Bearer JWT like /auth/jwt, then returns a new HS256 token inheriting its claims (new iss, iat, jti, exp).",
        "operationId": "postJwtExchange",
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "parameters": [
          {
            "name": "iss",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Required issuer"
          },
          {
            "name": "aud",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Required audience"
          }
        ],
        "responses": {
          "200": {
            "description": "Exchanged token",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "authenticated": {
                      "type": "boolean"
                    },
                    "auth_type": {
                      "type": "string"
                    },
                    "claims": {
                      "type": "object"
                    },
                    "exchanged_token": {
                      "type": "string"
                    }
                  }
                }
              },
              "application/xml": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "authenticated": {
                      "type": "boolean"
                    },
                    "auth_type": {
                      "type": "string"
                    },
                    "claims": {
                      "type": "object"
                    },
                    "exchanged_token": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid token",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AuthFailure"
                }
              },
              "application/xml": {
                "schema": {
                  "$ref": "#/components/schemas/AuthFailure"
                }
              }
            }
          }
        }
      },
      "get": {
        "tags": [
          "Auth"
        ],
        "summary": "JWT token exchange",
        "description": "Validates the Bearer JWT like /auth/jwt, then returns a new HS256 token inheriting its claims (new iss, iat, jti, exp).",
        "operationId": "postJwtExchange_get",
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "parameters": [
          {
            "name": "iss",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Required issuer"
          },
          {
            "name": "aud",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Required audience"
          }
        ],
        "responses": {
          "200": {
            "description": "Exchanged token",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "authenticated": {
                      "type": "boolean"
                    },
                    "auth_type": {
                      "type": "string"
                    },
                    "claims": {
                      "type": "object"
                    },
                    "exchanged_token": {
                      "type": "string"
                    }
                  }
                }
              },
              "application/xml": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "authenticated": {
                      "type": "boolean"
                    },
                    "auth_type": {
                      "type": "string"
                    },
                    "claims": {
                      "type": "object"
                    },
                    "exchanged_token": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid token",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AuthFailure"
                }
              },
              "application/xml": {
                "schema": {
                  "$ref": "#/components/schemas/AuthFailure"
                }
              }
            }
          }
        }
      },
      "put": {
        "tags": [
          "Auth"
        ],
        "summary": "JWT token exchange",
        "description": "Validates the Bearer JWT like /auth/jwt, then returns a new HS256 token inheriting its claims (new iss, iat, jti, exp).",
        "operationId": "postJwtExchange_put",
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "parameters": [
          {
            "name": "iss",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Required issuer"
          },
          {
            "name": "aud",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Required audience"
          }
        ],
        "responses": {
          "200": {
            "description": "Exchanged token",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "authenticated": {
                      "type": "boolean"
                    },
                    "auth_type": {
                      "type": "string"
                    },
                    "claims": {
                      "type": "object"
                    },
                    "exchanged_token": {
                      "type": "string"
                    }
                  }
                }
              },
              "application/xml": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "authenticated": {
                      "type": "boolean"
                    },
                    "auth_type": {
                      "type": "string"
                    },
                    "claims": {
                      "type": "object"
                    },
                    "exchanged_token": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid token",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AuthFailure"
                }
              },
              "application/xml": {
                "schema": {
                  "$ref": "#/components/schemas/AuthFailure"
                }
              }
            }
          }
        }
      },
      "patch": {
        "tags": [
          "Auth"
        ],
        "summary": "JWT token exchange",
        "description": "Validates the Bearer JWT like /auth/jwt, then returns a new HS256 token inheriting its claims (new iss, iat, jti, exp).",
        "operationId": "postJwtExchange_patch",
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "parameters": [
          {
            "name": "iss",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Required issuer"
          },
          {
            "name": "aud",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Required audience"
          }
        ],
        "responses": {
          "200": {
            "description": "Exchanged token",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "authenticated": {
                      "type": "boolean"
                    },
                    "auth_type": {
                      "type": "string"
                    },
                    "claims": {
                      "type": "object"
                    },
                    "exchanged_token": {
                      "type": "string"
                    }
                  }
                }
              },
              "application/xml": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "authenticated": {
                      "type": "boolean"
                    },
                    "auth_type": {
                      "type": "string"
                    },
                    "claims": {
                      "type": "object"
                    },
                    "exchanged_token": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid token",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AuthFailure"
                }
              },
              "application/xml": {
                "schema": {
                  "$ref": "#/components/schemas/AuthFailure"
                }
              }
            }
          }
        }
      },
      "delete": {
        "tags": [
          "Auth"
        ],
        "summary": "JWT token exchange",
        "description": "Validates the Bearer JWT like /auth/jwt, then returns a new HS256 token inheriting its claims (new iss, iat, jti, exp).",
        "operationId": "postJwtExchange_delete",
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "parameters": [
          {
            "name": "iss",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Required issuer"
          },
          {
            "name": "aud",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Required audience"
          }
        ],
        "responses": {
          "200": {
            "description": "Exchanged token",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "authenticated": {
                      "type": "boolean"
                    },
                    "auth_type": {
                      "type": "string"
                    },
                    "claims": {
                      "type": "object"
                    },
                    "exchanged_token": {
                      "type": "string"
                    }
                  }
                }
              },
              "application/xml": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "authenticated": {
                      "type": "boolean"
                    },
                    "auth_type": {
                      "type": "string"
                    },
                    "claims": {
                      "type": "object"
                    },
                    "exchanged_token": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid token",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AuthFailure"
                }
              },
              "application/xml": {
                "schema": {
                  "$ref": "#/components/schemas/AuthFailure"
                }
              }
            }
          }
        }
      }
    },
    "/.well-known/openid-configuration": {
      "get": {
        "tags": [
          "Auth"
        ],
        "summary": "OIDC discovery document",
        "operationId": "getOidcDiscovery",
        "responses": {
          "200": {
            "description": "Metadata",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          }
        }
      }
    },
    "/.well-known/oauth-authorization-server": {
      "get": {
        "tags": [
          "Auth"
        ],
        "summary": "OAuth 2.0 authorization server metadata (RFC 8414)",
        "operationId": "getOAuthServerMetadata",
        "responses": {
          "200": {
            "description": "Metadata",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          }
        }
      }
    },
    "/oauth/jwks": {
      "get": {
        "tags": [
          "Auth"
        ],
        "summary": "JWKS endpoint",
        "operationId": "getJwks",
        "description": "JSON Web Key Set with the RS256 public key.",
        "responses": {
          "200": {
            "description": "JWKS"
          }
        }
      }
    },
    "/oauth/token": {
      "post": {
        "tags": [
          "Auth"
        ],
        "summary": "OAuth 2.0 token endpoint",
        "description": "Grants: authorization_code (+PKCE), refresh_token (rotating), client_credentials, password, RFC 8693 token exchange. Client auth: client_secret_basic, client_secret_post, or client_id only for public clients. Responses carry Cache-Control: no-store.",
        "operationId": "postOAuthToken",
        "requestBody": {
          "required": true,
          "content": {
            "application/x-www-form-urlencoded": {
              "schema": {
                "type": "object",
                "required": [
                  "grant_type"
                ],
                "properties": {
                  "grant_type": {
                    "type": "string",
                    "enum": [
                      "authorization_code",
                      "client_credentials",
                      "password",
                      "refresh_token",
                      "urn:ietf:params:oauth:grant-type:token-exchange"
                    ]
                  },
                  "scope": {
                    "type": "string"
                  },
                  "resource": {
                    "type": "string",
                    "description": "RFC 8707 resource indicator (repeatable); becomes the access token aud"
                  },
                  "username": {
                    "type": "string",
                    "description": "password grant (demo/demo, alice/alice, bob/bob)"
                  },
                  "password": {
                    "type": "string",
                    "description": "password grant"
                  },
                  "code": {
                    "type": "string",
                    "description": "authorization_code grant"
                  },
                  "redirect_uri": {
                    "type": "string",
                    "description": "authorization_code grant (must match the authorization request)"
                  },
                  "code_verifier": {
                    "type": "string",
                    "description": "PKCE verifier"
                  },
                  "refresh_token": {
                    "type": "string",
                    "description": "refresh_token grant (rotated on use)"
                  },
                  "subject_token": {
                    "type": "string",
                    "description": "RFC 8693: token signed by this server"
                  },
                  "subject_token_type": {
                    "type": "string"
                  },
                  "actor_token": {
                    "type": "string"
                  },
                  "actor_token_type": {
                    "type": "string"
                  },
                  "audience": {
                    "type": "string",
                    "description": "RFC 8693 target audience (repeatable)"
                  },
                  "requested_token_type": {
                    "type": "string"
                  },
                  "client_id": {
                    "type": "string",
                    "example": "rustybin"
                  },
                  "client_secret": {
                    "type": "string",
                    "example": "secret"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Token response",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "access_token": {
                      "type": "string"
                    },
                    "token_type": {
                      "type": "string",
                      "example": "Bearer"
                    },
                    "expires_in": {
                      "type": "integer",
                      "example": 3600
                    },
                    "scope": {
                      "type": "string"
                    },
                    "id_token": {
                      "type": "string"
                    },
                    "refresh_token": {
                      "type": "string"
                    },
                    "issued_token_type": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "OAuth error (invalid_request, invalid_grant, unsupported_grant_type, invalid_scope, invalid_target, ...)",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "string",
                      "example": "invalid_request"
                    },
                    "error_description": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "invalid_client",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "string",
                      "example": "invalid_request"
                    },
                    "error_description": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/oauth/authorize": {
      "get": {
        "tags": [
          "Auth"
        ],
        "summary": "Authorization endpoint (login form)",
        "operationId": "getOAuthAuthorize",
        "parameters": [
          {
            "name": "response_type",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string",
              "enum": [
                "code"
              ]
            }
          },
          {
            "name": "client_id",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "redirect_uri",
            "in": "query",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "scope",
            "in": "query",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "state",
            "in": "query",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "nonce",
            "in": "query",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "code_challenge",
            "in": "query",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "code_challenge_method",
            "in": "query",
            "schema": {
              "type": "string",
              "enum": [
                "S256",
                "plain"
              ]
            }
          },
          {
            "name": "resource",
            "in": "query",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "login_hint",
            "in": "query",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "HTML login form"
          },
          "303": {
            "description": "Error redirect to the client"
          },
          "400": {
            "description": "Unknown client or invalid redirect_uri (HTML)"
          }
        }
      },
      "post": {
        "tags": [
          "Auth"
        ],
        "summary": "Authorization endpoint (submit login)",
        "operationId": "postOAuthAuthorize",
        "requestBody": {
          "required": true,
          "content": {
            "application/x-www-form-urlencoded": {
              "schema": {
                "type": "object",
                "required": [
                  "client_id",
                  "response_type",
                  "username",
                  "password"
                ],
                "properties": {
                  "username": {
                    "type": "string"
                  },
                  "password": {
                    "type": "string"
                  },
                  "client_id": {
                    "type": "string"
                  },
                  "redirect_uri": {
                    "type": "string"
                  },
                  "response_type": {
                    "type": "string"
                  },
                  "scope": {
                    "type": "string"
                  },
                  "state": {
                    "type": "string"
                  },
                  "nonce": {
                    "type": "string"
                  },
                  "code_challenge": {
                    "type": "string"
                  },
                  "code_challenge_method": {
                    "type": "string"
                  },
                  "resource": {
                    "type": "string"
                  },
                  "action": {
                    "type": "string",
                    "enum": [
                      "approve",
                      "deny"
                    ]
                  }
                }
              }
            }
          }
        },
        "responses": {
          "303": {
            "description": "Redirect with code and state (or an error)"
          },
          "401": {
            "description": "Invalid credentials (login form shown again)"
          }
        }
      }
    },
    "/oauth/userinfo": {
      "get": {
        "tags": [
          "Auth"
        ],
        "summary": "OIDC UserInfo",
        "operationId": "getOAuthUserinfo",
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "User claims",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "sub": {
                      "type": "string"
                    },
                    "name": {
                      "type": "string"
                    },
                    "preferred_username": {
                      "type": "string"
                    },
                    "email": {
                      "type": "string"
                    },
                    "email_verified": {
                      "type": "boolean"
                    },
                    "groups": {
                      "type": "array",
                      "items": {
                        "type": "string"
                      }
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid token",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "string",
                      "example": "invalid_request"
                    },
                    "error_description": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "insufficient_scope",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "string",
                      "example": "invalid_request"
                    },
                    "error_description": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          }
        }
      },
      "post": {
        "tags": [
          "Auth"
        ],
        "summary": "OIDC UserInfo (POST)",
        "operationId": "postOAuthUserinfo",
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "User claims"
          },
          "401": {
            "description": "Missing or invalid token",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "string",
                      "example": "invalid_request"
                    },
                    "error_description": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/oauth/introspect": {
      "post": {
        "tags": [
          "Auth"
        ],
        "summary": "Token introspection (RFC 7662)",
        "operationId": "postOAuthIntrospect",
        "requestBody": {
          "required": true,
          "content": {
            "application/x-www-form-urlencoded": {
              "schema": {
                "type": "object",
                "required": [
                  "token"
                ],
                "properties": {
                  "client_id": {
                    "type": "string",
                    "example": "rustybin"
                  },
                  "client_secret": {
                    "type": "string",
                    "example": "secret"
                  },
                  "token": {
                    "type": "string"
                  },
                  "token_type_hint": {
                    "type": "string"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Introspection result (active=false for anything invalid)",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "active": {
                      "type": "boolean"
                    },
                    "scope": {
                      "type": "string"
                    },
                    "client_id": {
                      "type": "string"
                    },
                    "username": {
                      "type": "string"
                    },
                    "token_type": {
                      "type": "string"
                    },
                    "exp": {
                      "type": "integer"
                    },
                    "iat": {
                      "type": "integer"
                    },
                    "sub": {
                      "type": "string"
                    },
                    "aud": {},
                    "iss": {
                      "type": "string"
                    },
                    "jti": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "invalid_client",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "string",
                      "example": "invalid_request"
                    },
                    "error_description": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/oauth/revoke": {
      "post": {
        "tags": [
          "Auth"
        ],
        "summary": "Token revocation (RFC 7009)",
        "operationId": "postOAuthRevoke",
        "requestBody": {
          "required": true,
          "content": {
            "application/x-www-form-urlencoded": {
              "schema": {
                "type": "object",
                "required": [
                  "token"
                ],
                "properties": {
                  "client_id": {
                    "type": "string",
                    "example": "rustybin"
                  },
                  "client_secret": {
                    "type": "string",
                    "example": "secret"
                  },
                  "token": {
                    "type": "string"
                  },
                  "token_type_hint": {
                    "type": "string"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Revoked (or the token was already invalid)"
          },
          "401": {
            "description": "invalid_client",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "string",
                      "example": "invalid_request"
                    },
                    "error_description": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/oauth/register": {
      "post": {
        "tags": [
          "Auth"
        ],
        "summary": "Dynamic client registration (RFC 7591)",
        "operationId": "postOAuthRegister",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "redirect_uris": {
                    "type": "array",
                    "items": {
                      "type": "string"
                    }
                  },
                  "client_name": {
                    "type": "string"
                  },
                  "grant_types": {
                    "type": "array",
                    "items": {
                      "type": "string"
                    }
                  },
                  "response_types": {
                    "type": "array",
                    "items": {
                      "type": "string"
                    }
                  },
                  "token_endpoint_auth_method": {
                    "type": "string",
                    "enum": [
                      "client_secret_basic",
                      "client_secret_post",
                      "none"
                    ]
                  },
                  "scope": {
                    "type": "string"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Registered client (client_id, client_secret, client_secret_expires_at, metadata)"
          },
          "400": {
            "description": "invalid_redirect_uri or invalid_client_metadata",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "string",
                      "example": "invalid_request"
                    },
                    "error_description": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/auth/mtls": {
      "get": {
        "tags": [
          "Auth"
        ],
        "summary": "Mutual TLS authentication",
        "description": "Uses the TLS client certificate on the HTTPS listener (verified against the demo CA during the handshake). Otherwise, when RUSTYBIN_MTLS_IN_HEADER is set, reads the certificate forwarded in that header (URL-encoded PEM, PEM or base64 DER) and verifies it was issued by the demo CA and is within its validity period.",
        "operationId": "getMtls",
        "responses": {
          "200": {
            "description": "Authenticated",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AuthResponse"
                }
              },
              "application/xml": {
                "schema": {
                  "$ref": "#/components/schemas/AuthResponse"
                }
              }
            }
          },
          "401": {
            "description": "Missing, invalid or untrusted client certificate"
          }
        }
      },
      "post": {
        "tags": [
          "Auth"
        ],
        "summary": "Mutual TLS authentication",
        "description": "Uses the TLS client certificate on the HTTPS listener (verified against the demo CA during the handshake). Otherwise, when RUSTYBIN_MTLS_IN_HEADER is set, reads the certificate forwarded in that header (URL-encoded PEM, PEM or base64 DER) and verifies it was issued by the demo CA and is within its validity period.",
        "operationId": "getMtls_post",
        "responses": {
          "200": {
            "description": "Authenticated",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AuthResponse"
                }
              },
              "application/xml": {
                "schema": {
                  "$ref": "#/components/schemas/AuthResponse"
                }
              }
            }
          },
          "401": {
            "description": "Missing, invalid or untrusted client certificate"
          }
        }
      },
      "put": {
        "tags": [
          "Auth"
        ],
        "summary": "Mutual TLS authentication",
        "description": "Uses the TLS client certificate on the HTTPS listener (verified against the demo CA during the handshake). Otherwise, when RUSTYBIN_MTLS_IN_HEADER is set, reads the certificate forwarded in that header (URL-encoded PEM, PEM or base64 DER) and verifies it was issued by the demo CA and is within its validity period.",
        "operationId": "getMtls_put",
        "responses": {
          "200": {
            "description": "Authenticated",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AuthResponse"
                }
              },
              "application/xml": {
                "schema": {
                  "$ref": "#/components/schemas/AuthResponse"
                }
              }
            }
          },
          "401": {
            "description": "Missing, invalid or untrusted client certificate"
          }
        }
      },
      "patch": {
        "tags": [
          "Auth"
        ],
        "summary": "Mutual TLS authentication",
        "description": "Uses the TLS client certificate on the HTTPS listener (verified against the demo CA during the handshake). Otherwise, when RUSTYBIN_MTLS_IN_HEADER is set, reads the certificate forwarded in that header (URL-encoded PEM, PEM or base64 DER) and verifies it was issued by the demo CA and is within its validity period.",
        "operationId": "getMtls_patch",
        "responses": {
          "200": {
            "description": "Authenticated",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AuthResponse"
                }
              },
              "application/xml": {
                "schema": {
                  "$ref": "#/components/schemas/AuthResponse"
                }
              }
            }
          },
          "401": {
            "description": "Missing, invalid or untrusted client certificate"
          }
        }
      },
      "delete": {
        "tags": [
          "Auth"
        ],
        "summary": "Mutual TLS authentication",
        "description": "Uses the TLS client certificate on the HTTPS listener (verified against the demo CA during the handshake). Otherwise, when RUSTYBIN_MTLS_IN_HEADER is set, reads the certificate forwarded in that header (URL-encoded PEM, PEM or base64 DER) and verifies it was issued by the demo CA and is within its validity period.",
        "operationId": "getMtls_delete",
        "responses": {
          "200": {
            "description": "Authenticated",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AuthResponse"
                }
              },
              "application/xml": {
                "schema": {
                  "$ref": "#/components/schemas/AuthResponse"
                }
              }
            }
          },
          "401": {
            "description": "Missing, invalid or untrusted client certificate"
          }
        }
      }
    },
    "/auth/mtls/get-client-cert": {
      "get": {
        "tags": [
          "Auth"
        ],
        "summary": "Get demo client certificate",
        "description": "Returns a demo client certificate (CN demo-client, issued by the demo CA) and its private key.",
        "operationId": "getMtlsClientCert",
        "responses": {
          "200": {
            "description": "Client cert and key PEM",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "cert_pem": {
                      "type": "string"
                    },
                    "key_pem": {
                      "type": "string"
                    },
                    "usage": {
                      "type": "string"
                    }
                  }
                }
              },
              "application/xml": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "cert_pem": {
                      "type": "string"
                    },
                    "key_pem": {
                      "type": "string"
                    },
                    "usage": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/auth/mtls/get-ca-cert": {
      "get": {
        "tags": [
          "Auth"
        ],
        "summary": "Get demo CA certificate",
        "description": "Returns the demo CA certificate for configuring trust in your API gateway. The CA is persisted next to the TLS certificate when that directory is writable.",
        "operationId": "getMtlsCaCert",
        "responses": {
          "200": {
            "description": "CA certificate PEM",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "ca_cert_pem": {
                      "type": "string"
                    },
                    "usage": {
                      "type": "string"
                    }
                  }
                }
              },
              "application/xml": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "ca_cert_pem": {
                      "type": "string"
                    },
                    "usage": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/mcp": {
      "post": {
        "tags": [
          "MCP"
        ],
        "summary": "MCP: send a JSON-RPC message",
        "operationId": "mcpPost",
        "parameters": [
          {
            "name": "MCP-Protocol-Version",
            "in": "header",
            "required": false,
            "schema": {
              "type": "string",
              "example": "2026-07-28"
            }
          },
          {
            "name": "Mcp-Method",
            "in": "header",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Required on 2026-07-28 requests; must equal the body method"
          },
          {
            "name": "Mcp-Name",
            "in": "header",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "tools/call, prompts/get, resources/read (2026-07-28)"
          },
          {
            "name": "Mcp-Session-Id",
            "in": "header",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Session from initialize (2025-xx)"
          },
          {
            "name": "page_size",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/McpJsonRpcMessage"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "JSON-RPC response (application/json) or SSE stream (text/event-stream)",
            "content": {
              "application/json": {},
              "text/event-stream": {}
            }
          },
          "202": {
            "description": "Notification or response accepted"
          },
          "400": {
            "description": "Invalid message, header mismatch (-32020), unsupported version (-32022), missing session"
          },
          "401": {
            "description": "Authentication required"
          },
          "403": {
            "description": "Origin not allowed or insufficient scope"
          },
          "404": {
            "description": "Unknown method (-32601, 2026-07-28) or unknown session"
          },
          "406": {
            "description": "Accept does not allow JSON or SSE"
          }
        }
      },
      "get": {
        "tags": [
          "MCP"
        ],
        "summary": "MCP: open the server-to-client SSE stream (2025-xx sessions)",
        "operationId": "mcpStream",
        "parameters": [
          {
            "name": "MCP-Protocol-Version",
            "in": "header",
            "required": false,
            "schema": {
              "type": "string",
              "example": "2026-07-28"
            }
          },
          {
            "name": "Mcp-Method",
            "in": "header",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Required on 2026-07-28 requests; must equal the body method"
          },
          {
            "name": "Mcp-Name",
            "in": "header",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "tools/call, prompts/get, resources/read (2026-07-28)"
          },
          {
            "name": "Mcp-Session-Id",
            "in": "header",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Session from initialize (2025-xx)"
          },
          {
            "name": "page_size",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "JSON-RPC response (application/json) or SSE stream (text/event-stream)",
            "content": {
              "application/json": {},
              "text/event-stream": {}
            }
          },
          "202": {
            "description": "Notification or response accepted"
          },
          "400": {
            "description": "Invalid message, header mismatch (-32020), unsupported version (-32022), missing session"
          },
          "401": {
            "description": "Authentication required"
          },
          "403": {
            "description": "Origin not allowed or insufficient scope"
          },
          "404": {
            "description": "Unknown method (-32601, 2026-07-28) or unknown session"
          },
          "406": {
            "description": "Accept does not allow JSON or SSE"
          }
        }
      },
      "delete": {
        "tags": [
          "MCP"
        ],
        "summary": "MCP: terminate the session (2025-xx)",
        "operationId": "mcpDelete",
        "parameters": [
          {
            "name": "MCP-Protocol-Version",
            "in": "header",
            "required": false,
            "schema": {
              "type": "string",
              "example": "2026-07-28"
            }
          },
          {
            "name": "Mcp-Method",
            "in": "header",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Required on 2026-07-28 requests; must equal the body method"
          },
          {
            "name": "Mcp-Name",
            "in": "header",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "tools/call, prompts/get, resources/read (2026-07-28)"
          },
          {
            "name": "Mcp-Session-Id",
            "in": "header",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Session from initialize (2025-xx)"
          },
          {
            "name": "page_size",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "JSON-RPC response (application/json) or SSE stream (text/event-stream)",
            "content": {
              "application/json": {},
              "text/event-stream": {}
            }
          },
          "202": {
            "description": "Notification or response accepted"
          },
          "400": {
            "description": "Invalid message, header mismatch (-32020), unsupported version (-32022), missing session"
          },
          "401": {
            "description": "Authentication required"
          },
          "403": {
            "description": "Origin not allowed or insufficient scope"
          },
          "404": {
            "description": "Unknown method (-32601, 2026-07-28) or unknown session"
          },
          "406": {
            "description": "Accept does not allow JSON or SSE"
          }
        }
      }
    },
    "/mcp/protected": {
      "post": {
        "tags": [
          "MCP"
        ],
        "summary": "Protected MCP: send a JSON-RPC message",
        "operationId": "mcpProtectedPost",
        "parameters": [
          {
            "name": "MCP-Protocol-Version",
            "in": "header",
            "required": false,
            "schema": {
              "type": "string",
              "example": "2026-07-28"
            }
          },
          {
            "name": "Mcp-Method",
            "in": "header",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Required on 2026-07-28 requests; must equal the body method"
          },
          {
            "name": "Mcp-Name",
            "in": "header",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "tools/call, prompts/get, resources/read (2026-07-28)"
          },
          {
            "name": "Mcp-Session-Id",
            "in": "header",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Session from initialize (2025-xx)"
          },
          {
            "name": "page_size",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/McpJsonRpcMessage"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "JSON-RPC response (application/json) or SSE stream (text/event-stream)",
            "content": {
              "application/json": {},
              "text/event-stream": {}
            }
          },
          "202": {
            "description": "Notification or response accepted"
          },
          "400": {
            "description": "Invalid message, header mismatch (-32020), unsupported version (-32022), missing session"
          },
          "401": {
            "description": "Authentication required"
          },
          "403": {
            "description": "Origin not allowed or insufficient scope"
          },
          "404": {
            "description": "Unknown method (-32601, 2026-07-28) or unknown session"
          },
          "406": {
            "description": "Accept does not allow JSON or SSE"
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ]
      },
      "get": {
        "tags": [
          "MCP"
        ],
        "summary": "Protected MCP: open the server-to-client SSE stream (2025-xx sessions)",
        "operationId": "mcpProtectedStream",
        "parameters": [
          {
            "name": "MCP-Protocol-Version",
            "in": "header",
            "required": false,
            "schema": {
              "type": "string",
              "example": "2026-07-28"
            }
          },
          {
            "name": "Mcp-Method",
            "in": "header",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Required on 2026-07-28 requests; must equal the body method"
          },
          {
            "name": "Mcp-Name",
            "in": "header",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "tools/call, prompts/get, resources/read (2026-07-28)"
          },
          {
            "name": "Mcp-Session-Id",
            "in": "header",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Session from initialize (2025-xx)"
          },
          {
            "name": "page_size",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer"
            }
          }
        ],
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "JSON-RPC response (application/json) or SSE stream (text/event-stream)",
            "content": {
              "application/json": {},
              "text/event-stream": {}
            }
          },
          "202": {
            "description": "Notification or response accepted"
          },
          "400": {
            "description": "Invalid message, header mismatch (-32020), unsupported version (-32022), missing session"
          },
          "401": {
            "description": "Authentication required"
          },
          "403": {
            "description": "Origin not allowed or insufficient scope"
          },
          "404": {
            "description": "Unknown method (-32601, 2026-07-28) or unknown session"
          },
          "406": {
            "description": "Accept does not allow JSON or SSE"
          }
        }
      },
      "delete": {
        "tags": [
          "MCP"
        ],
        "summary": "Protected MCP: terminate the session (2025-xx)",
        "operationId": "mcpProtectedDelete",
        "parameters": [
          {
            "name": "MCP-Protocol-Version",
            "in": "header",
            "required": false,
            "schema": {
              "type": "string",
              "example": "2026-07-28"
            }
          },
          {
            "name": "Mcp-Method",
            "in": "header",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Required on 2026-07-28 requests; must equal the body method"
          },
          {
            "name": "Mcp-Name",
            "in": "header",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "tools/call, prompts/get, resources/read (2026-07-28)"
          },
          {
            "name": "Mcp-Session-Id",
            "in": "header",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Session from initialize (2025-xx)"
          },
          {
            "name": "page_size",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer"
            }
          }
        ],
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "JSON-RPC response (application/json) or SSE stream (text/event-stream)",
            "content": {
              "application/json": {},
              "text/event-stream": {}
            }
          },
          "202": {
            "description": "Notification or response accepted"
          },
          "400": {
            "description": "Invalid message, header mismatch (-32020), unsupported version (-32022), missing session"
          },
          "401": {
            "description": "Authentication required"
          },
          "403": {
            "description": "Origin not allowed or insufficient scope"
          },
          "404": {
            "description": "Unknown method (-32601, 2026-07-28) or unknown session"
          },
          "406": {
            "description": "Accept does not allow JSON or SSE"
          }
        }
      }
    },
    "/mcp/apikey": {
      "post": {
        "tags": [
          "MCP"
        ],
        "summary": "API key MCP: send a JSON-RPC message",
        "operationId": "mcpApiKeyPost",
        "parameters": [
          {
            "name": "MCP-Protocol-Version",
            "in": "header",
            "required": false,
            "schema": {
              "type": "string",
              "example": "2026-07-28"
            }
          },
          {
            "name": "Mcp-Method",
            "in": "header",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Required on 2026-07-28 requests; must equal the body method"
          },
          {
            "name": "Mcp-Name",
            "in": "header",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "tools/call, prompts/get, resources/read (2026-07-28)"
          },
          {
            "name": "Mcp-Session-Id",
            "in": "header",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Session from initialize (2025-xx)"
          },
          {
            "name": "page_size",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/McpJsonRpcMessage"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "JSON-RPC response (application/json) or SSE stream (text/event-stream)",
            "content": {
              "application/json": {},
              "text/event-stream": {}
            }
          },
          "202": {
            "description": "Notification or response accepted"
          },
          "400": {
            "description": "Invalid message, header mismatch (-32020), unsupported version (-32022), missing session"
          },
          "401": {
            "description": "Authentication required"
          },
          "403": {
            "description": "Origin not allowed or insufficient scope"
          },
          "404": {
            "description": "Unknown method (-32601, 2026-07-28) or unknown session"
          },
          "406": {
            "description": "Accept does not allow JSON or SSE"
          }
        },
        "security": [
          {
            "mcpApiKey": []
          }
        ]
      },
      "get": {
        "tags": [
          "MCP"
        ],
        "summary": "API key MCP: open the server-to-client SSE stream (2025-xx sessions)",
        "operationId": "mcpApiKeyStream",
        "parameters": [
          {
            "name": "MCP-Protocol-Version",
            "in": "header",
            "required": false,
            "schema": {
              "type": "string",
              "example": "2026-07-28"
            }
          },
          {
            "name": "Mcp-Method",
            "in": "header",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Required on 2026-07-28 requests; must equal the body method"
          },
          {
            "name": "Mcp-Name",
            "in": "header",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "tools/call, prompts/get, resources/read (2026-07-28)"
          },
          {
            "name": "Mcp-Session-Id",
            "in": "header",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Session from initialize (2025-xx)"
          },
          {
            "name": "page_size",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer"
            }
          }
        ],
        "security": [
          {
            "mcpApiKey": []
          }
        ],
        "responses": {
          "200": {
            "description": "JSON-RPC response (application/json) or SSE stream (text/event-stream)",
            "content": {
              "application/json": {},
              "text/event-stream": {}
            }
          },
          "202": {
            "description": "Notification or response accepted"
          },
          "400": {
            "description": "Invalid message, header mismatch (-32020), unsupported version (-32022), missing session"
          },
          "401": {
            "description": "Authentication required"
          },
          "403": {
            "description": "Origin not allowed or insufficient scope"
          },
          "404": {
            "description": "Unknown method (-32601, 2026-07-28) or unknown session"
          },
          "406": {
            "description": "Accept does not allow JSON or SSE"
          }
        }
      },
      "delete": {
        "tags": [
          "MCP"
        ],
        "summary": "API key MCP: terminate the session (2025-xx)",
        "operationId": "mcpApiKeyDelete",
        "parameters": [
          {
            "name": "MCP-Protocol-Version",
            "in": "header",
            "required": false,
            "schema": {
              "type": "string",
              "example": "2026-07-28"
            }
          },
          {
            "name": "Mcp-Method",
            "in": "header",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Required on 2026-07-28 requests; must equal the body method"
          },
          {
            "name": "Mcp-Name",
            "in": "header",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "tools/call, prompts/get, resources/read (2026-07-28)"
          },
          {
            "name": "Mcp-Session-Id",
            "in": "header",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Session from initialize (2025-xx)"
          },
          {
            "name": "page_size",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer"
            }
          }
        ],
        "security": [
          {
            "mcpApiKey": []
          }
        ],
        "responses": {
          "200": {
            "description": "JSON-RPC response (application/json) or SSE stream (text/event-stream)",
            "content": {
              "application/json": {},
              "text/event-stream": {}
            }
          },
          "202": {
            "description": "Notification or response accepted"
          },
          "400": {
            "description": "Invalid message, header mismatch (-32020), unsupported version (-32022), missing session"
          },
          "401": {
            "description": "Authentication required"
          },
          "403": {
            "description": "Origin not allowed or insufficient scope"
          },
          "404": {
            "description": "Unknown method (-32601, 2026-07-28) or unknown session"
          },
          "406": {
            "description": "Accept does not allow JSON or SSE"
          }
        }
      }
    },
    "/mcp/servers/{name}": {
      "post": {
        "tags": [
          "MCP"
        ],
        "summary": "Named MCP server: send a JSON-RPC message",
        "operationId": "mcpNamedServerPost",
        "parameters": [
          {
            "name": "name",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "enum": [
                "weather",
                "crm",
                "devtools"
              ]
            }
          },
          {
            "name": "MCP-Protocol-Version",
            "in": "header",
            "required": false,
            "schema": {
              "type": "string",
              "example": "2026-07-28"
            }
          },
          {
            "name": "Mcp-Method",
            "in": "header",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Required on 2026-07-28 requests; must equal the body method"
          },
          {
            "name": "Mcp-Name",
            "in": "header",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "tools/call, prompts/get, resources/read (2026-07-28)"
          },
          {
            "name": "Mcp-Session-Id",
            "in": "header",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Session from initialize (2025-xx)"
          },
          {
            "name": "page_size",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/McpJsonRpcMessage"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "JSON-RPC response (application/json) or SSE stream (text/event-stream)",
            "content": {
              "application/json": {},
              "text/event-stream": {}
            }
          },
          "202": {
            "description": "Notification or response accepted"
          },
          "400": {
            "description": "Invalid message, header mismatch (-32020), unsupported version (-32022), missing session"
          },
          "401": {
            "description": "Authentication required"
          },
          "403": {
            "description": "Origin not allowed or insufficient scope"
          },
          "404": {
            "description": "Unknown method (-32601, 2026-07-28) or unknown session"
          },
          "406": {
            "description": "Accept does not allow JSON or SSE"
          }
        }
      },
      "get": {
        "tags": [
          "MCP"
        ],
        "summary": "Named MCP server: open the server-to-client SSE stream (2025-xx sessions)",
        "operationId": "mcpNamedServerStream",
        "parameters": [
          {
            "name": "name",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "enum": [
                "weather",
                "crm",
                "devtools"
              ]
            }
          },
          {
            "name": "MCP-Protocol-Version",
            "in": "header",
            "required": false,
            "schema": {
              "type": "string",
              "example": "2026-07-28"
            }
          },
          {
            "name": "Mcp-Method",
            "in": "header",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Required on 2026-07-28 requests; must equal the body method"
          },
          {
            "name": "Mcp-Name",
            "in": "header",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "tools/call, prompts/get, resources/read (2026-07-28)"
          },
          {
            "name": "Mcp-Session-Id",
            "in": "header",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Session from initialize (2025-xx)"
          },
          {
            "name": "page_size",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "JSON-RPC response (application/json) or SSE stream (text/event-stream)",
            "content": {
              "application/json": {},
              "text/event-stream": {}
            }
          },
          "202": {
            "description": "Notification or response accepted"
          },
          "400": {
            "description": "Invalid message, header mismatch (-32020), unsupported version (-32022), missing session"
          },
          "401": {
            "description": "Authentication required"
          },
          "403": {
            "description": "Origin not allowed or insufficient scope"
          },
          "404": {
            "description": "Unknown method (-32601, 2026-07-28) or unknown session"
          },
          "406": {
            "description": "Accept does not allow JSON or SSE"
          }
        }
      },
      "delete": {
        "tags": [
          "MCP"
        ],
        "summary": "Named MCP server: terminate the session (2025-xx)",
        "operationId": "mcpNamedServerDelete",
        "parameters": [
          {
            "name": "name",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "enum": [
                "weather",
                "crm",
                "devtools"
              ]
            }
          },
          {
            "name": "MCP-Protocol-Version",
            "in": "header",
            "required": false,
            "schema": {
              "type": "string",
              "example": "2026-07-28"
            }
          },
          {
            "name": "Mcp-Method",
            "in": "header",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Required on 2026-07-28 requests; must equal the body method"
          },
          {
            "name": "Mcp-Name",
            "in": "header",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "tools/call, prompts/get, resources/read (2026-07-28)"
          },
          {
            "name": "Mcp-Session-Id",
            "in": "header",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Session from initialize (2025-xx)"
          },
          {
            "name": "page_size",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "JSON-RPC response (application/json) or SSE stream (text/event-stream)",
            "content": {
              "application/json": {},
              "text/event-stream": {}
            }
          },
          "202": {
            "description": "Notification or response accepted"
          },
          "400": {
            "description": "Invalid message, header mismatch (-32020), unsupported version (-32022), missing session"
          },
          "401": {
            "description": "Authentication required"
          },
          "403": {
            "description": "Origin not allowed or insufficient scope"
          },
          "404": {
            "description": "Unknown method (-32601, 2026-07-28) or unknown session"
          },
          "406": {
            "description": "Accept does not allow JSON or SSE"
          }
        }
      }
    },
    "/mock/{name}/_rustybin/mcp": {
      "post": {
        "tags": [
          "Mocks"
        ],
        "summary": "OpenAPI mock MCP server: send a JSON-RPC message",
        "operationId": "mockMcpPost",
        "parameters": [
          {
            "name": "name",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "The mock's name"
          },
          {
            "name": "MCP-Protocol-Version",
            "in": "header",
            "required": false,
            "schema": {
              "type": "string",
              "example": "2026-07-28"
            }
          },
          {
            "name": "Mcp-Method",
            "in": "header",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Required on 2026-07-28 requests; must equal the body method"
          },
          {
            "name": "Mcp-Name",
            "in": "header",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "tools/call, prompts/get, resources/read (2026-07-28)"
          },
          {
            "name": "Mcp-Session-Id",
            "in": "header",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Session from initialize (2025-xx)"
          },
          {
            "name": "page_size",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/McpJsonRpcMessage"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "JSON-RPC response (application/json) or SSE stream (text/event-stream)",
            "content": {
              "application/json": {},
              "text/event-stream": {}
            }
          },
          "202": {
            "description": "Notification or response accepted"
          },
          "400": {
            "description": "Invalid message, header mismatch (-32020), unsupported version (-32022), missing session"
          },
          "401": {
            "description": "Authentication required"
          },
          "403": {
            "description": "Origin not allowed or insufficient scope"
          },
          "404": {
            "description": "Unknown method (-32601, 2026-07-28) or unknown session"
          },
          "406": {
            "description": "Accept does not allow JSON or SSE"
          }
        }
      },
      "get": {
        "tags": [
          "Mocks"
        ],
        "summary": "OpenAPI mock MCP server: open the server-to-client SSE stream (2025-xx sessions)",
        "operationId": "mockMcpStream",
        "parameters": [
          {
            "name": "name",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "The mock's name"
          },
          {
            "name": "MCP-Protocol-Version",
            "in": "header",
            "required": false,
            "schema": {
              "type": "string",
              "example": "2026-07-28"
            }
          },
          {
            "name": "Mcp-Method",
            "in": "header",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Required on 2026-07-28 requests; must equal the body method"
          },
          {
            "name": "Mcp-Name",
            "in": "header",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "tools/call, prompts/get, resources/read (2026-07-28)"
          },
          {
            "name": "Mcp-Session-Id",
            "in": "header",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Session from initialize (2025-xx)"
          },
          {
            "name": "page_size",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "JSON-RPC response (application/json) or SSE stream (text/event-stream)",
            "content": {
              "application/json": {},
              "text/event-stream": {}
            }
          },
          "202": {
            "description": "Notification or response accepted"
          },
          "400": {
            "description": "Invalid message, header mismatch (-32020), unsupported version (-32022), missing session"
          },
          "401": {
            "description": "Authentication required"
          },
          "403": {
            "description": "Origin not allowed or insufficient scope"
          },
          "404": {
            "description": "Unknown method (-32601, 2026-07-28) or unknown session"
          },
          "406": {
            "description": "Accept does not allow JSON or SSE"
          }
        }
      },
      "delete": {
        "tags": [
          "Mocks"
        ],
        "summary": "OpenAPI mock MCP server: terminate the session (2025-xx)",
        "operationId": "mockMcpDelete",
        "parameters": [
          {
            "name": "name",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "The mock's name"
          },
          {
            "name": "MCP-Protocol-Version",
            "in": "header",
            "required": false,
            "schema": {
              "type": "string",
              "example": "2026-07-28"
            }
          },
          {
            "name": "Mcp-Method",
            "in": "header",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Required on 2026-07-28 requests; must equal the body method"
          },
          {
            "name": "Mcp-Name",
            "in": "header",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "tools/call, prompts/get, resources/read (2026-07-28)"
          },
          {
            "name": "Mcp-Session-Id",
            "in": "header",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Session from initialize (2025-xx)"
          },
          {
            "name": "page_size",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "JSON-RPC response (application/json) or SSE stream (text/event-stream)",
            "content": {
              "application/json": {},
              "text/event-stream": {}
            }
          },
          "202": {
            "description": "Notification or response accepted"
          },
          "400": {
            "description": "Invalid message, header mismatch (-32020), unsupported version (-32022), missing session"
          },
          "401": {
            "description": "Authentication required"
          },
          "403": {
            "description": "Origin not allowed or insufficient scope"
          },
          "404": {
            "description": "Unknown method (-32601, 2026-07-28) or unknown session"
          },
          "406": {
            "description": "Accept does not allow JSON or SSE"
          }
        }
      }
    },
    "/mcp/sse": {
      "get": {
        "tags": [
          "MCP"
        ],
        "summary": "Legacy HTTP+SSE transport (2024-11-05) event stream",
        "operationId": "mcpLegacySse",
        "responses": {
          "200": {
            "description": "SSE stream; first event `endpoint`",
            "content": {
              "text/event-stream": {}
            }
          }
        }
      }
    },
    "/mcp/messages": {
      "post": {
        "tags": [
          "MCP"
        ],
        "summary": "Legacy HTTP+SSE transport (2024-11-05) message endpoint",
        "operationId": "mcpLegacyMessages",
        "parameters": [
          {
            "name": "sessionId",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/McpJsonRpcMessage"
              }
            }
          }
        },
        "responses": {
          "202": {
            "description": "Accepted; the reply arrives on the SSE stream"
          },
          "400": {
            "description": "Invalid JSON-RPC"
          },
          "404": {
            "description": "Unknown session"
          }
        }
      }
    },
    "/.well-known/oauth-protected-resource": {
      "get": {
        "tags": [
          "MCP"
        ],
        "summary": "OAuth 2.0 Protected Resource Metadata (RFC 9728) for /mcp/protected",
        "responses": {
          "200": {
            "description": "Metadata document",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "resource": {
                      "type": "string"
                    },
                    "authorization_servers": {
                      "type": "array",
                      "items": {
                        "type": "string"
                      }
                    },
                    "scopes_supported": {
                      "type": "array",
                      "items": {
                        "type": "string"
                      }
                    },
                    "bearer_methods_supported": {
                      "type": "array",
                      "items": {
                        "type": "string"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "operationId": "mcpProtectedResourceMetadata"
      }
    },
    "/.well-known/oauth-protected-resource/mcp/protected": {
      "get": {
        "tags": [
          "MCP"
        ],
        "summary": "OAuth 2.0 Protected Resource Metadata (RFC 9728) for /mcp/protected",
        "responses": {
          "200": {
            "description": "Metadata document",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "resource": {
                      "type": "string"
                    },
                    "authorization_servers": {
                      "type": "array",
                      "items": {
                        "type": "string"
                      }
                    },
                    "scopes_supported": {
                      "type": "array",
                      "items": {
                        "type": "string"
                      }
                    },
                    "bearer_methods_supported": {
                      "type": "array",
                      "items": {
                        "type": "string"
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "operationId": "mcpProtectedResourceMetadataPath"
      }
    },
    "/.well-known/oauth-protected-resource/mock/{name}/_rustybin/mcp": {
      "get": {
        "tags": [
          "MCP"
        ],
        "summary": "Protected resource metadata of a mock with mcp.oauth",
        "operationId": "getMockMcpResourceMetadata",
        "parameters": [
          {
            "name": "name",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "RFC 9728 metadata"
          },
          "404": {
            "description": "No such mock, or it does not ask for a token"
          }
        }
      }
    },
    "/ai/openai/v1/chat/completions": {
      "post": {
        "tags": [
          "AI Gateway"
        ],
        "summary": "Chat completions (OpenAI-compatible)",
        "operationId": "openaiChatCompletions",
        "parameters": [
          {
            "name": "X-Rustybin-Mode",
            "in": "header",
            "schema": {
              "type": "string",
              "enum": [
                "canned",
                "echo",
                "scripted",
                "random"
              ]
            },
            "description": "Reply mode (also selectable by a model name segment, e.g. rustybin-echo)"
          },
          {
            "name": "X-Rustybin-Latency-Ms",
            "in": "header",
            "schema": {
              "type": "integer"
            },
            "description": "Delay before response headers"
          },
          {
            "name": "X-Rustybin-TTFT-Ms",
            "in": "header",
            "schema": {
              "type": "integer"
            },
            "description": "Time to first token"
          },
          {
            "name": "X-Rustybin-Tokens-Per-Second",
            "in": "header",
            "schema": {
              "type": "integer"
            },
            "description": "Streaming pace (default 100, 0 = unpaced)"
          },
          {
            "name": "X-Rustybin-Fail",
            "in": "header",
            "schema": {
              "type": "string"
            },
            "description": "kind[:percent]: 429, 500, 503, 529, 504, context_length, content_filter, prompt_filter, 401, ... in the provider's native error shape"
          },
          {
            "name": "X-Rustybin-Require-Auth",
            "in": "header",
            "schema": {
              "type": "boolean"
            },
            "description": "Enforce the provider's native credential"
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ChatCompletionResponse"
                }
              },
              "text/event-stream": {
                "schema": {
                  "type": "string",
                  "description": "chat.completion.chunk events, then data: [DONE]"
                }
              }
            }
          },
          "400": {
            "description": "Invalid request (OpenAI error shape)"
          },
          "401": {
            "description": "Missing or invalid credential (when required)"
          },
          "429": {
            "description": "Simulated rate limit"
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ChatCompletionRequest"
              }
            }
          }
        }
      }
    },
    "/ai/v1/chat/completions": {
      "post": {
        "tags": [
          "AI Gateway"
        ],
        "summary": "Chat completions (OpenAI-compatible)",
        "operationId": "postChatCompletions",
        "parameters": [
          {
            "name": "X-Rustybin-Mode",
            "in": "header",
            "schema": {
              "type": "string",
              "enum": [
                "canned",
                "echo",
                "scripted",
                "random"
              ]
            },
            "description": "Reply mode (also selectable by a model name segment, e.g. rustybin-echo)"
          },
          {
            "name": "X-Rustybin-Latency-Ms",
            "in": "header",
            "schema": {
              "type": "integer"
            },
            "description": "Delay before response headers"
          },
          {
            "name": "X-Rustybin-TTFT-Ms",
            "in": "header",
            "schema": {
              "type": "integer"
            },
            "description": "Time to first token"
          },
          {
            "name": "X-Rustybin-Tokens-Per-Second",
            "in": "header",
            "schema": {
              "type": "integer"
            },
            "description": "Streaming pace (default 100, 0 = unpaced)"
          },
          {
            "name": "X-Rustybin-Fail",
            "in": "header",
            "schema": {
              "type": "string"
            },
            "description": "kind[:percent]: 429, 500, 503, 529, 504, context_length, content_filter, prompt_filter, 401, ... in the provider's native error shape"
          },
          {
            "name": "X-Rustybin-Require-Auth",
            "in": "header",
            "schema": {
              "type": "boolean"
            },
            "description": "Enforce the provider's native credential"
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ChatCompletionResponse"
                }
              },
              "text/event-stream": {
                "schema": {
                  "type": "string",
                  "description": "chat.completion.chunk events, then data: [DONE]"
                }
              }
            }
          },
          "400": {
            "description": "Invalid request (OpenAI error shape)"
          },
          "401": {
            "description": "Missing or invalid credential (when required)"
          },
          "429": {
            "description": "Simulated rate limit"
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ChatCompletionRequest"
              }
            }
          }
        }
      }
    },
    "/ai/openai/v1/completions": {
      "post": {
        "tags": [
          "AI Gateway"
        ],
        "summary": "Legacy text completions",
        "operationId": "openaiCompletions",
        "parameters": [
          {
            "name": "X-Rustybin-Mode",
            "in": "header",
            "schema": {
              "type": "string",
              "enum": [
                "canned",
                "echo",
                "scripted",
                "random"
              ]
            },
            "description": "Reply mode (also selectable by a model name segment, e.g. rustybin-echo)"
          },
          {
            "name": "X-Rustybin-Latency-Ms",
            "in": "header",
            "schema": {
              "type": "integer"
            },
            "description": "Delay before response headers"
          },
          {
            "name": "X-Rustybin-TTFT-Ms",
            "in": "header",
            "schema": {
              "type": "integer"
            },
            "description": "Time to first token"
          },
          {
            "name": "X-Rustybin-Tokens-Per-Second",
            "in": "header",
            "schema": {
              "type": "integer"
            },
            "description": "Streaming pace (default 100, 0 = unpaced)"
          },
          {
            "name": "X-Rustybin-Fail",
            "in": "header",
            "schema": {
              "type": "string"
            },
            "description": "kind[:percent]: 429, 500, 503, 529, 504, context_length, content_filter, prompt_filter, 401, ... in the provider's native error shape"
          },
          {
            "name": "X-Rustybin-Require-Auth",
            "in": "header",
            "schema": {
              "type": "boolean"
            },
            "description": "Enforce the provider's native credential"
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "400": {
            "description": "Invalid request (OpenAI error shape)"
          },
          "401": {
            "description": "Missing or invalid credential (when required)"
          },
          "429": {
            "description": "Simulated rate limit"
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "model": {
                    "type": "string"
                  },
                  "prompt": {
                    "oneOf": [
                      {
                        "type": "string"
                      },
                      {
                        "type": "array",
                        "items": {}
                      }
                    ]
                  },
                  "max_tokens": {
                    "type": "integer"
                  },
                  "stream": {
                    "type": "boolean"
                  },
                  "echo": {
                    "type": "boolean"
                  },
                  "suffix": {
                    "type": "string"
                  },
                  "n": {
                    "type": "integer"
                  }
                }
              }
            }
          }
        }
      }
    },
    "/ai/v1/completions": {
      "post": {
        "tags": [
          "AI Gateway"
        ],
        "summary": "Legacy text completions",
        "operationId": "postCompletions",
        "parameters": [
          {
            "name": "X-Rustybin-Mode",
            "in": "header",
            "schema": {
              "type": "string",
              "enum": [
                "canned",
                "echo",
                "scripted",
                "random"
              ]
            },
            "description": "Reply mode (also selectable by a model name segment, e.g. rustybin-echo)"
          },
          {
            "name": "X-Rustybin-Latency-Ms",
            "in": "header",
            "schema": {
              "type": "integer"
            },
            "description": "Delay before response headers"
          },
          {
            "name": "X-Rustybin-TTFT-Ms",
            "in": "header",
            "schema": {
              "type": "integer"
            },
            "description": "Time to first token"
          },
          {
            "name": "X-Rustybin-Tokens-Per-Second",
            "in": "header",
            "schema": {
              "type": "integer"
            },
            "description": "Streaming pace (default 100, 0 = unpaced)"
          },
          {
            "name": "X-Rustybin-Fail",
            "in": "header",
            "schema": {
              "type": "string"
            },
            "description": "kind[:percent]: 429, 500, 503, 529, 504, context_length, content_filter, prompt_filter, 401, ... in the provider's native error shape"
          },
          {
            "name": "X-Rustybin-Require-Auth",
            "in": "header",
            "schema": {
              "type": "boolean"
            },
            "description": "Enforce the provider's native credential"
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "400": {
            "description": "Invalid request (OpenAI error shape)"
          },
          "401": {
            "description": "Missing or invalid credential (when required)"
          },
          "429": {
            "description": "Simulated rate limit"
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "model": {
                    "type": "string"
                  },
                  "prompt": {
                    "oneOf": [
                      {
                        "type": "string"
                      },
                      {
                        "type": "array",
                        "items": {}
                      }
                    ]
                  },
                  "max_tokens": {
                    "type": "integer"
                  },
                  "stream": {
                    "type": "boolean"
                  },
                  "echo": {
                    "type": "boolean"
                  },
                  "suffix": {
                    "type": "string"
                  },
                  "n": {
                    "type": "integer"
                  }
                }
              }
            }
          }
        }
      }
    },
    "/ai/openai/v1/embeddings": {
      "post": {
        "tags": [
          "AI Gateway"
        ],
        "summary": "Embeddings",
        "operationId": "openaiEmbeddings",
        "parameters": [
          {
            "name": "X-Rustybin-Mode",
            "in": "header",
            "schema": {
              "type": "string",
              "enum": [
                "canned",
                "echo",
                "scripted",
                "random"
              ]
            },
            "description": "Reply mode (also selectable by a model name segment, e.g. rustybin-echo)"
          },
          {
            "name": "X-Rustybin-Latency-Ms",
            "in": "header",
            "schema": {
              "type": "integer"
            },
            "description": "Delay before response headers"
          },
          {
            "name": "X-Rustybin-TTFT-Ms",
            "in": "header",
            "schema": {
              "type": "integer"
            },
            "description": "Time to first token"
          },
          {
            "name": "X-Rustybin-Tokens-Per-Second",
            "in": "header",
            "schema": {
              "type": "integer"
            },
            "description": "Streaming pace (default 100, 0 = unpaced)"
          },
          {
            "name": "X-Rustybin-Fail",
            "in": "header",
            "schema": {
              "type": "string"
            },
            "description": "kind[:percent]: 429, 500, 503, 529, 504, context_length, content_filter, prompt_filter, 401, ... in the provider's native error shape"
          },
          {
            "name": "X-Rustybin-Require-Auth",
            "in": "header",
            "schema": {
              "type": "boolean"
            },
            "description": "Enforce the provider's native credential"
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "object": {
                      "type": "string"
                    },
                    "data": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "index": {
                            "type": "integer"
                          },
                          "embedding": {
                            "oneOf": [
                              {
                                "type": "array",
                                "items": {
                                  "type": "number"
                                }
                              },
                              {
                                "type": "string"
                              }
                            ]
                          }
                        }
                      }
                    },
                    "usage": {
                      "type": "object"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Invalid request (OpenAI error shape)"
          },
          "401": {
            "description": "Missing or invalid credential (when required)"
          },
          "429": {
            "description": "Simulated rate limit"
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "input"
                ],
                "properties": {
                  "model": {
                    "type": "string",
                    "example": "text-embedding-3-small"
                  },
                  "input": {
                    "oneOf": [
                      {
                        "type": "string"
                      },
                      {
                        "type": "array",
                        "items": {}
                      }
                    ]
                  },
                  "dimensions": {
                    "type": "integer"
                  },
                  "encoding_format": {
                    "type": "string",
                    "enum": [
                      "float",
                      "base64"
                    ]
                  }
                }
              }
            }
          }
        }
      }
    },
    "/ai/v1/embeddings": {
      "post": {
        "tags": [
          "AI Gateway"
        ],
        "summary": "Embeddings",
        "operationId": "postEmbeddings",
        "parameters": [
          {
            "name": "X-Rustybin-Mode",
            "in": "header",
            "schema": {
              "type": "string",
              "enum": [
                "canned",
                "echo",
                "scripted",
                "random"
              ]
            },
            "description": "Reply mode (also selectable by a model name segment, e.g. rustybin-echo)"
          },
          {
            "name": "X-Rustybin-Latency-Ms",
            "in": "header",
            "schema": {
              "type": "integer"
            },
            "description": "Delay before response headers"
          },
          {
            "name": "X-Rustybin-TTFT-Ms",
            "in": "header",
            "schema": {
              "type": "integer"
            },
            "description": "Time to first token"
          },
          {
            "name": "X-Rustybin-Tokens-Per-Second",
            "in": "header",
            "schema": {
              "type": "integer"
            },
            "description": "Streaming pace (default 100, 0 = unpaced)"
          },
          {
            "name": "X-Rustybin-Fail",
            "in": "header",
            "schema": {
              "type": "string"
            },
            "description": "kind[:percent]: 429, 500, 503, 529, 504, context_length, content_filter, prompt_filter, 401, ... in the provider's native error shape"
          },
          {
            "name": "X-Rustybin-Require-Auth",
            "in": "header",
            "schema": {
              "type": "boolean"
            },
            "description": "Enforce the provider's native credential"
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "object": {
                      "type": "string"
                    },
                    "data": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "index": {
                            "type": "integer"
                          },
                          "embedding": {
                            "oneOf": [
                              {
                                "type": "array",
                                "items": {
                                  "type": "number"
                                }
                              },
                              {
                                "type": "string"
                              }
                            ]
                          }
                        }
                      }
                    },
                    "usage": {
                      "type": "object"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Invalid request (OpenAI error shape)"
          },
          "401": {
            "description": "Missing or invalid credential (when required)"
          },
          "429": {
            "description": "Simulated rate limit"
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "input"
                ],
                "properties": {
                  "model": {
                    "type": "string",
                    "example": "text-embedding-3-small"
                  },
                  "input": {
                    "oneOf": [
                      {
                        "type": "string"
                      },
                      {
                        "type": "array",
                        "items": {}
                      }
                    ]
                  },
                  "dimensions": {
                    "type": "integer"
                  },
                  "encoding_format": {
                    "type": "string",
                    "enum": [
                      "float",
                      "base64"
                    ]
                  }
                }
              }
            }
          }
        }
      }
    },
    "/ai/openai/v1/models": {
      "get": {
        "tags": [
          "AI Gateway"
        ],
        "summary": "List models",
        "operationId": "openaiListModels",
        "responses": {
          "200": {
            "description": "Model list"
          }
        }
      }
    },
    "/ai/v1/models": {
      "get": {
        "tags": [
          "AI Gateway"
        ],
        "summary": "List models",
        "operationId": "getModels",
        "responses": {
          "200": {
            "description": "Model list"
          }
        }
      }
    },
    "/ai/openai/v1/models/{model}": {
      "get": {
        "tags": [
          "AI Gateway"
        ],
        "summary": "Retrieve a model",
        "operationId": "openaiGetModel",
        "parameters": [
          {
            "name": "model",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Model"
          },
          "404": {
            "description": "Unknown model"
          }
        }
      }
    },
    "/ai/v1/models/{model}": {
      "get": {
        "tags": [
          "AI Gateway"
        ],
        "summary": "Retrieve a model",
        "operationId": "getModel",
        "parameters": [
          {
            "name": "model",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Model"
          },
          "404": {
            "description": "Unknown model"
          }
        }
      }
    },
    "/ai/openai/v1/moderations": {
      "post": {
        "tags": [
          "AI Gateway"
        ],
        "summary": "Moderations",
        "operationId": "openaiModerations",
        "parameters": [
          {
            "name": "X-Rustybin-Mode",
            "in": "header",
            "schema": {
              "type": "string",
              "enum": [
                "canned",
                "echo",
                "scripted",
                "random"
              ]
            },
            "description": "Reply mode (also selectable by a model name segment, e.g. rustybin-echo)"
          },
          {
            "name": "X-Rustybin-Latency-Ms",
            "in": "header",
            "schema": {
              "type": "integer"
            },
            "description": "Delay before response headers"
          },
          {
            "name": "X-Rustybin-TTFT-Ms",
            "in": "header",
            "schema": {
              "type": "integer"
            },
            "description": "Time to first token"
          },
          {
            "name": "X-Rustybin-Tokens-Per-Second",
            "in": "header",
            "schema": {
              "type": "integer"
            },
            "description": "Streaming pace (default 100, 0 = unpaced)"
          },
          {
            "name": "X-Rustybin-Fail",
            "in": "header",
            "schema": {
              "type": "string"
            },
            "description": "kind[:percent]: 429, 500, 503, 529, 504, context_length, content_filter, prompt_filter, 401, ... in the provider's native error shape"
          },
          {
            "name": "X-Rustybin-Require-Auth",
            "in": "header",
            "schema": {
              "type": "boolean"
            },
            "description": "Enforce the provider's native credential"
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "id": {
                      "type": "string"
                    },
                    "model": {
                      "type": "string"
                    },
                    "results": {
                      "type": "array",
                      "items": {
                        "type": "object"
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Invalid request (OpenAI error shape)"
          },
          "401": {
            "description": "Missing or invalid credential (when required)"
          },
          "429": {
            "description": "Simulated rate limit"
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "input"
                ],
                "properties": {
                  "input": {
                    "oneOf": [
                      {
                        "type": "string"
                      },
                      {
                        "type": "array",
                        "items": {}
                      }
                    ]
                  },
                  "model": {
                    "type": "string"
                  }
                }
              }
            }
          }
        }
      }
    },
    "/ai/v1/moderations": {
      "post": {
        "tags": [
          "AI Gateway"
        ],
        "summary": "Moderations",
        "operationId": "postModerations",
        "parameters": [
          {
            "name": "X-Rustybin-Mode",
            "in": "header",
            "schema": {
              "type": "string",
              "enum": [
                "canned",
                "echo",
                "scripted",
                "random"
              ]
            },
            "description": "Reply mode (also selectable by a model name segment, e.g. rustybin-echo)"
          },
          {
            "name": "X-Rustybin-Latency-Ms",
            "in": "header",
            "schema": {
              "type": "integer"
            },
            "description": "Delay before response headers"
          },
          {
            "name": "X-Rustybin-TTFT-Ms",
            "in": "header",
            "schema": {
              "type": "integer"
            },
            "description": "Time to first token"
          },
          {
            "name": "X-Rustybin-Tokens-Per-Second",
            "in": "header",
            "schema": {
              "type": "integer"
            },
            "description": "Streaming pace (default 100, 0 = unpaced)"
          },
          {
            "name": "X-Rustybin-Fail",
            "in": "header",
            "schema": {
              "type": "string"
            },
            "description": "kind[:percent]: 429, 500, 503, 529, 504, context_length, content_filter, prompt_filter, 401, ... in the provider's native error shape"
          },
          {
            "name": "X-Rustybin-Require-Auth",
            "in": "header",
            "schema": {
              "type": "boolean"
            },
            "description": "Enforce the provider's native credential"
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "id": {
                      "type": "string"
                    },
                    "model": {
                      "type": "string"
                    },
                    "results": {
                      "type": "array",
                      "items": {
                        "type": "object"
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Invalid request (OpenAI error shape)"
          },
          "401": {
            "description": "Missing or invalid credential (when required)"
          },
          "429": {
            "description": "Simulated rate limit"
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "input"
                ],
                "properties": {
                  "input": {
                    "oneOf": [
                      {
                        "type": "string"
                      },
                      {
                        "type": "array",
                        "items": {}
                      }
                    ]
                  },
                  "model": {
                    "type": "string"
                  }
                }
              }
            }
          }
        }
      }
    },
    "/ai/openai/v1/images/generations": {
      "post": {
        "tags": [
          "AI Gateway"
        ],
        "summary": "Image generation",
        "operationId": "openaiImages",
        "parameters": [
          {
            "name": "X-Rustybin-Mode",
            "in": "header",
            "schema": {
              "type": "string",
              "enum": [
                "canned",
                "echo",
                "scripted",
                "random"
              ]
            },
            "description": "Reply mode (also selectable by a model name segment, e.g. rustybin-echo)"
          },
          {
            "name": "X-Rustybin-Latency-Ms",
            "in": "header",
            "schema": {
              "type": "integer"
            },
            "description": "Delay before response headers"
          },
          {
            "name": "X-Rustybin-TTFT-Ms",
            "in": "header",
            "schema": {
              "type": "integer"
            },
            "description": "Time to first token"
          },
          {
            "name": "X-Rustybin-Tokens-Per-Second",
            "in": "header",
            "schema": {
              "type": "integer"
            },
            "description": "Streaming pace (default 100, 0 = unpaced)"
          },
          {
            "name": "X-Rustybin-Fail",
            "in": "header",
            "schema": {
              "type": "string"
            },
            "description": "kind[:percent]: 429, 500, 503, 529, 504, context_length, content_filter, prompt_filter, 401, ... in the provider's native error shape"
          },
          {
            "name": "X-Rustybin-Require-Auth",
            "in": "header",
            "schema": {
              "type": "boolean"
            },
            "description": "Enforce the provider's native credential"
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "created": {
                      "type": "integer"
                    },
                    "data": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "url": {
                            "type": "string"
                          },
                          "b64_json": {
                            "type": "string"
                          }
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Invalid request (OpenAI error shape)"
          },
          "401": {
            "description": "Missing or invalid credential (when required)"
          },
          "429": {
            "description": "Simulated rate limit"
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "prompt"
                ],
                "properties": {
                  "prompt": {
                    "type": "string"
                  },
                  "model": {
                    "type": "string"
                  },
                  "n": {
                    "type": "integer"
                  },
                  "size": {
                    "type": "string"
                  },
                  "response_format": {
                    "type": "string",
                    "enum": [
                      "url",
                      "b64_json"
                    ]
                  }
                }
              }
            }
          }
        }
      }
    },
    "/ai/v1/images/generations": {
      "post": {
        "tags": [
          "AI Gateway"
        ],
        "summary": "Image generation",
        "operationId": "postImages",
        "parameters": [
          {
            "name": "X-Rustybin-Mode",
            "in": "header",
            "schema": {
              "type": "string",
              "enum": [
                "canned",
                "echo",
                "scripted",
                "random"
              ]
            },
            "description": "Reply mode (also selectable by a model name segment, e.g. rustybin-echo)"
          },
          {
            "name": "X-Rustybin-Latency-Ms",
            "in": "header",
            "schema": {
              "type": "integer"
            },
            "description": "Delay before response headers"
          },
          {
            "name": "X-Rustybin-TTFT-Ms",
            "in": "header",
            "schema": {
              "type": "integer"
            },
            "description": "Time to first token"
          },
          {
            "name": "X-Rustybin-Tokens-Per-Second",
            "in": "header",
            "schema": {
              "type": "integer"
            },
            "description": "Streaming pace (default 100, 0 = unpaced)"
          },
          {
            "name": "X-Rustybin-Fail",
            "in": "header",
            "schema": {
              "type": "string"
            },
            "description": "kind[:percent]: 429, 500, 503, 529, 504, context_length, content_filter, prompt_filter, 401, ... in the provider's native error shape"
          },
          {
            "name": "X-Rustybin-Require-Auth",
            "in": "header",
            "schema": {
              "type": "boolean"
            },
            "description": "Enforce the provider's native credential"
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "created": {
                      "type": "integer"
                    },
                    "data": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "url": {
                            "type": "string"
                          },
                          "b64_json": {
                            "type": "string"
                          }
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Invalid request (OpenAI error shape)"
          },
          "401": {
            "description": "Missing or invalid credential (when required)"
          },
          "429": {
            "description": "Simulated rate limit"
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "prompt"
                ],
                "properties": {
                  "prompt": {
                    "type": "string"
                  },
                  "model": {
                    "type": "string"
                  },
                  "n": {
                    "type": "integer"
                  },
                  "size": {
                    "type": "string"
                  },
                  "response_format": {
                    "type": "string",
                    "enum": [
                      "url",
                      "b64_json"
                    ]
                  }
                }
              }
            }
          }
        }
      }
    },
    "/ai/openai/v1/audio/transcriptions": {
      "post": {
        "tags": [
          "AI Gateway"
        ],
        "summary": "Audio transcription",
        "operationId": "openaiTranscriptions",
        "parameters": [
          {
            "name": "X-Rustybin-Mode",
            "in": "header",
            "schema": {
              "type": "string",
              "enum": [
                "canned",
                "echo",
                "scripted",
                "random"
              ]
            },
            "description": "Reply mode (also selectable by a model name segment, e.g. rustybin-echo)"
          },
          {
            "name": "X-Rustybin-Latency-Ms",
            "in": "header",
            "schema": {
              "type": "integer"
            },
            "description": "Delay before response headers"
          },
          {
            "name": "X-Rustybin-TTFT-Ms",
            "in": "header",
            "schema": {
              "type": "integer"
            },
            "description": "Time to first token"
          },
          {
            "name": "X-Rustybin-Tokens-Per-Second",
            "in": "header",
            "schema": {
              "type": "integer"
            },
            "description": "Streaming pace (default 100, 0 = unpaced)"
          },
          {
            "name": "X-Rustybin-Fail",
            "in": "header",
            "schema": {
              "type": "string"
            },
            "description": "kind[:percent]: 429, 500, 503, 529, 504, context_length, content_filter, prompt_filter, 401, ... in the provider's native error shape"
          },
          {
            "name": "X-Rustybin-Require-Auth",
            "in": "header",
            "schema": {
              "type": "boolean"
            },
            "description": "Enforce the provider's native credential"
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "text": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Invalid request (OpenAI error shape)"
          },
          "401": {
            "description": "Missing or invalid credential (when required)"
          },
          "429": {
            "description": "Simulated rate limit"
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "multipart/form-data": {
              "schema": {
                "type": "object",
                "required": [
                  "file",
                  "model"
                ],
                "properties": {
                  "file": {
                    "type": "string",
                    "format": "binary"
                  },
                  "model": {
                    "type": "string"
                  },
                  "response_format": {
                    "type": "string",
                    "enum": [
                      "json",
                      "text",
                      "srt",
                      "verbose_json",
                      "vtt"
                    ]
                  },
                  "language": {
                    "type": "string"
                  }
                }
              }
            }
          }
        }
      }
    },
    "/ai/v1/audio/transcriptions": {
      "post": {
        "tags": [
          "AI Gateway"
        ],
        "summary": "Audio transcription",
        "operationId": "postTranscriptions",
        "parameters": [
          {
            "name": "X-Rustybin-Mode",
            "in": "header",
            "schema": {
              "type": "string",
              "enum": [
                "canned",
                "echo",
                "scripted",
                "random"
              ]
            },
            "description": "Reply mode (also selectable by a model name segment, e.g. rustybin-echo)"
          },
          {
            "name": "X-Rustybin-Latency-Ms",
            "in": "header",
            "schema": {
              "type": "integer"
            },
            "description": "Delay before response headers"
          },
          {
            "name": "X-Rustybin-TTFT-Ms",
            "in": "header",
            "schema": {
              "type": "integer"
            },
            "description": "Time to first token"
          },
          {
            "name": "X-Rustybin-Tokens-Per-Second",
            "in": "header",
            "schema": {
              "type": "integer"
            },
            "description": "Streaming pace (default 100, 0 = unpaced)"
          },
          {
            "name": "X-Rustybin-Fail",
            "in": "header",
            "schema": {
              "type": "string"
            },
            "description": "kind[:percent]: 429, 500, 503, 529, 504, context_length, content_filter, prompt_filter, 401, ... in the provider's native error shape"
          },
          {
            "name": "X-Rustybin-Require-Auth",
            "in": "header",
            "schema": {
              "type": "boolean"
            },
            "description": "Enforce the provider's native credential"
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "text": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Invalid request (OpenAI error shape)"
          },
          "401": {
            "description": "Missing or invalid credential (when required)"
          },
          "429": {
            "description": "Simulated rate limit"
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "multipart/form-data": {
              "schema": {
                "type": "object",
                "required": [
                  "file",
                  "model"
                ],
                "properties": {
                  "file": {
                    "type": "string",
                    "format": "binary"
                  },
                  "model": {
                    "type": "string"
                  },
                  "response_format": {
                    "type": "string",
                    "enum": [
                      "json",
                      "text",
                      "srt",
                      "verbose_json",
                      "vtt"
                    ]
                  },
                  "language": {
                    "type": "string"
                  }
                }
              }
            }
          }
        }
      }
    },
    "/ai/openai/v1/responses": {
      "post": {
        "tags": [
          "AI Gateway"
        ],
        "summary": "Responses API (OpenAI-compatible)",
        "operationId": "openaiResponses",
        "parameters": [
          {
            "name": "X-Rustybin-Mode",
            "in": "header",
            "schema": {
              "type": "string",
              "enum": [
                "canned",
                "echo",
                "scripted",
                "random"
              ]
            },
            "description": "Reply mode (also selectable by a model name segment, e.g. rustybin-echo)"
          },
          {
            "name": "X-Rustybin-Latency-Ms",
            "in": "header",
            "schema": {
              "type": "integer"
            },
            "description": "Delay before response headers"
          },
          {
            "name": "X-Rustybin-TTFT-Ms",
            "in": "header",
            "schema": {
              "type": "integer"
            },
            "description": "Time to first token"
          },
          {
            "name": "X-Rustybin-Tokens-Per-Second",
            "in": "header",
            "schema": {
              "type": "integer"
            },
            "description": "Streaming pace (default 100, 0 = unpaced)"
          },
          {
            "name": "X-Rustybin-Fail",
            "in": "header",
            "schema": {
              "type": "string"
            },
            "description": "kind[:percent]: 429, 500, 503, 529, 504, context_length, content_filter, prompt_filter, 401, ... in the provider's native error shape"
          },
          {
            "name": "X-Rustybin-Require-Auth",
            "in": "header",
            "schema": {
              "type": "boolean"
            },
            "description": "Enforce the provider's native credential"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "input"
                ],
                "properties": {
                  "model": {
                    "type": "string"
                  },
                  "input": {
                    "oneOf": [
                      {
                        "type": "string"
                      },
                      {
                        "type": "array",
                        "items": {
                          "type": "object"
                        }
                      }
                    ]
                  },
                  "instructions": {
                    "type": "string"
                  },
                  "tools": {
                    "type": "array",
                    "items": {
                      "type": "object"
                    }
                  },
                  "tool_choice": {},
                  "text": {
                    "type": "object",
                    "properties": {
                      "format": {
                        "type": "object"
                      }
                    }
                  },
                  "max_output_tokens": {
                    "type": "integer"
                  },
                  "stream": {
                    "type": "boolean"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Response object, or text/event-stream with response.* events",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "id": {
                      "type": "string"
                    },
                    "object": {
                      "type": "string"
                    },
                    "status": {
                      "type": "string"
                    },
                    "output": {
                      "type": "array",
                      "items": {
                        "type": "object"
                      }
                    },
                    "usage": {
                      "type": "object"
                    }
                  }
                }
              },
              "text/event-stream": {
                "schema": {
                  "type": "string"
                }
              }
            }
          },
          "400": {
            "description": "Invalid request"
          }
        }
      }
    },
    "/ai/v1/responses": {
      "post": {
        "tags": [
          "AI Gateway"
        ],
        "summary": "Responses API (OpenAI-compatible)",
        "operationId": "postResponses",
        "parameters": [
          {
            "name": "X-Rustybin-Mode",
            "in": "header",
            "schema": {
              "type": "string",
              "enum": [
                "canned",
                "echo",
                "scripted",
                "random"
              ]
            },
            "description": "Reply mode (also selectable by a model name segment, e.g. rustybin-echo)"
          },
          {
            "name": "X-Rustybin-Latency-Ms",
            "in": "header",
            "schema": {
              "type": "integer"
            },
            "description": "Delay before response headers"
          },
          {
            "name": "X-Rustybin-TTFT-Ms",
            "in": "header",
            "schema": {
              "type": "integer"
            },
            "description": "Time to first token"
          },
          {
            "name": "X-Rustybin-Tokens-Per-Second",
            "in": "header",
            "schema": {
              "type": "integer"
            },
            "description": "Streaming pace (default 100, 0 = unpaced)"
          },
          {
            "name": "X-Rustybin-Fail",
            "in": "header",
            "schema": {
              "type": "string"
            },
            "description": "kind[:percent]: 429, 500, 503, 529, 504, context_length, content_filter, prompt_filter, 401, ... in the provider's native error shape"
          },
          {
            "name": "X-Rustybin-Require-Auth",
            "in": "header",
            "schema": {
              "type": "boolean"
            },
            "description": "Enforce the provider's native credential"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "input"
                ],
                "properties": {
                  "model": {
                    "type": "string"
                  },
                  "input": {
                    "oneOf": [
                      {
                        "type": "string"
                      },
                      {
                        "type": "array",
                        "items": {
                          "type": "object"
                        }
                      }
                    ]
                  },
                  "instructions": {
                    "type": "string"
                  },
                  "tools": {
                    "type": "array",
                    "items": {
                      "type": "object"
                    }
                  },
                  "tool_choice": {},
                  "text": {
                    "type": "object",
                    "properties": {
                      "format": {
                        "type": "object"
                      }
                    }
                  },
                  "max_output_tokens": {
                    "type": "integer"
                  },
                  "stream": {
                    "type": "boolean"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Response object, or text/event-stream with response.* events",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "id": {
                      "type": "string"
                    },
                    "object": {
                      "type": "string"
                    },
                    "status": {
                      "type": "string"
                    },
                    "output": {
                      "type": "array",
                      "items": {
                        "type": "object"
                      }
                    },
                    "usage": {
                      "type": "object"
                    }
                  }
                }
              },
              "text/event-stream": {
                "schema": {
                  "type": "string"
                }
              }
            }
          },
          "400": {
            "description": "Invalid request"
          }
        }
      }
    },
    "/ai/azure/openai/deployments/{deployment}/chat/completions": {
      "post": {
        "tags": [
          "AI Gateway"
        ],
        "summary": "Azure OpenAI chat completions",
        "operationId": "azureChatCompletions",
        "parameters": [
          {
            "name": "deployment",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "api-version",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string",
              "example": "2024-10-21"
            }
          },
          {
            "name": "api-key",
            "in": "header",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "X-Rustybin-Mode",
            "in": "header",
            "schema": {
              "type": "string",
              "enum": [
                "canned",
                "echo",
                "scripted",
                "random"
              ]
            },
            "description": "Reply mode (also selectable by a model name segment, e.g. rustybin-echo)"
          },
          {
            "name": "X-Rustybin-Latency-Ms",
            "in": "header",
            "schema": {
              "type": "integer"
            },
            "description": "Delay before response headers"
          },
          {
            "name": "X-Rustybin-TTFT-Ms",
            "in": "header",
            "schema": {
              "type": "integer"
            },
            "description": "Time to first token"
          },
          {
            "name": "X-Rustybin-Tokens-Per-Second",
            "in": "header",
            "schema": {
              "type": "integer"
            },
            "description": "Streaming pace (default 100, 0 = unpaced)"
          },
          {
            "name": "X-Rustybin-Fail",
            "in": "header",
            "schema": {
              "type": "string"
            },
            "description": "kind[:percent]: 429, 500, 503, 529, 504, context_length, content_filter, prompt_filter, 401, ... in the provider's native error shape"
          },
          {
            "name": "X-Rustybin-Require-Auth",
            "in": "header",
            "schema": {
              "type": "boolean"
            },
            "description": "Enforce the provider's native credential"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ChatCompletionRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK (OpenAI shape with Azure content filter annotations)"
          },
          "400": {
            "description": "Missing api-version or invalid request"
          },
          "401": {
            "description": "Missing or invalid api-key (when required)"
          }
        }
      }
    },
    "/ai/azure/openai/deployments/{deployment}/completions": {
      "post": {
        "tags": [
          "AI Gateway"
        ],
        "summary": "Azure OpenAI completions",
        "operationId": "azureCompletions",
        "parameters": [
          {
            "name": "deployment",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "api-version",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string",
              "example": "2024-10-21"
            }
          },
          {
            "name": "api-key",
            "in": "header",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "X-Rustybin-Mode",
            "in": "header",
            "schema": {
              "type": "string",
              "enum": [
                "canned",
                "echo",
                "scripted",
                "random"
              ]
            },
            "description": "Reply mode (also selectable by a model name segment, e.g. rustybin-echo)"
          },
          {
            "name": "X-Rustybin-Latency-Ms",
            "in": "header",
            "schema": {
              "type": "integer"
            },
            "description": "Delay before response headers"
          },
          {
            "name": "X-Rustybin-TTFT-Ms",
            "in": "header",
            "schema": {
              "type": "integer"
            },
            "description": "Time to first token"
          },
          {
            "name": "X-Rustybin-Tokens-Per-Second",
            "in": "header",
            "schema": {
              "type": "integer"
            },
            "description": "Streaming pace (default 100, 0 = unpaced)"
          },
          {
            "name": "X-Rustybin-Fail",
            "in": "header",
            "schema": {
              "type": "string"
            },
            "description": "kind[:percent]: 429, 500, 503, 529, 504, context_length, content_filter, prompt_filter, 401, ... in the provider's native error shape"
          },
          {
            "name": "X-Rustybin-Require-Auth",
            "in": "header",
            "schema": {
              "type": "boolean"
            },
            "description": "Enforce the provider's native credential"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "prompt": {}
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK (OpenAI shape with Azure content filter annotations)"
          },
          "400": {
            "description": "Missing api-version or invalid request"
          },
          "401": {
            "description": "Missing or invalid api-key (when required)"
          }
        }
      }
    },
    "/ai/azure/openai/deployments/{deployment}/embeddings": {
      "post": {
        "tags": [
          "AI Gateway"
        ],
        "summary": "Azure OpenAI embeddings",
        "operationId": "azureEmbeddings",
        "parameters": [
          {
            "name": "deployment",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "api-version",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string",
              "example": "2024-10-21"
            }
          },
          {
            "name": "api-key",
            "in": "header",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "X-Rustybin-Mode",
            "in": "header",
            "schema": {
              "type": "string",
              "enum": [
                "canned",
                "echo",
                "scripted",
                "random"
              ]
            },
            "description": "Reply mode (also selectable by a model name segment, e.g. rustybin-echo)"
          },
          {
            "name": "X-Rustybin-Latency-Ms",
            "in": "header",
            "schema": {
              "type": "integer"
            },
            "description": "Delay before response headers"
          },
          {
            "name": "X-Rustybin-TTFT-Ms",
            "in": "header",
            "schema": {
              "type": "integer"
            },
            "description": "Time to first token"
          },
          {
            "name": "X-Rustybin-Tokens-Per-Second",
            "in": "header",
            "schema": {
              "type": "integer"
            },
            "description": "Streaming pace (default 100, 0 = unpaced)"
          },
          {
            "name": "X-Rustybin-Fail",
            "in": "header",
            "schema": {
              "type": "string"
            },
            "description": "kind[:percent]: 429, 500, 503, 529, 504, context_length, content_filter, prompt_filter, 401, ... in the provider's native error shape"
          },
          {
            "name": "X-Rustybin-Require-Auth",
            "in": "header",
            "schema": {
              "type": "boolean"
            },
            "description": "Enforce the provider's native credential"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "input": {}
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK (OpenAI shape with Azure content filter annotations)"
          },
          "400": {
            "description": "Missing api-version or invalid request"
          },
          "401": {
            "description": "Missing or invalid api-key (when required)"
          }
        }
      }
    },
    "/ai/anthropic/v1/messages": {
      "post": {
        "tags": [
          "AI Gateway"
        ],
        "summary": "Anthropic Messages API (mock)",
        "operationId": "anthropicMessages",
        "parameters": [
          {
            "name": "x-api-key",
            "in": "header",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "anthropic-version",
            "in": "header",
            "schema": {
              "type": "string",
              "example": "2023-06-01"
            }
          },
          {
            "name": "X-Rustybin-Mode",
            "in": "header",
            "schema": {
              "type": "string",
              "enum": [
                "canned",
                "echo",
                "scripted",
                "random"
              ]
            },
            "description": "Reply mode (also selectable by a model name segment, e.g. rustybin-echo)"
          },
          {
            "name": "X-Rustybin-Latency-Ms",
            "in": "header",
            "schema": {
              "type": "integer"
            },
            "description": "Delay before response headers"
          },
          {
            "name": "X-Rustybin-TTFT-Ms",
            "in": "header",
            "schema": {
              "type": "integer"
            },
            "description": "Time to first token"
          },
          {
            "name": "X-Rustybin-Tokens-Per-Second",
            "in": "header",
            "schema": {
              "type": "integer"
            },
            "description": "Streaming pace (default 100, 0 = unpaced)"
          },
          {
            "name": "X-Rustybin-Fail",
            "in": "header",
            "schema": {
              "type": "string"
            },
            "description": "kind[:percent]: 429, 500, 503, 529, 504, context_length, content_filter, prompt_filter, 401, ... in the provider's native error shape"
          },
          {
            "name": "X-Rustybin-Require-Auth",
            "in": "header",
            "schema": {
              "type": "boolean"
            },
            "description": "Enforce the provider's native credential"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/AnthropicMessagesRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Message, or text/event-stream when stream=true",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AnthropicMessage"
                }
              },
              "text/event-stream": {
                "schema": {
                  "type": "string"
                }
              }
            }
          },
          "400": {
            "description": "invalid_request_error (e.g. missing max_tokens)"
          },
          "401": {
            "description": "authentication_error (when required)"
          },
          "529": {
            "description": "overloaded_error (simulated)"
          }
        }
      }
    },
    "/ai/anthropic/v1/messages/count_tokens": {
      "post": {
        "tags": [
          "AI Gateway"
        ],
        "summary": "Count input tokens",
        "operationId": "anthropicCountTokens",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/AnthropicMessagesRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Token count",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "input_tokens": {
                      "type": "integer"
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/ai/anthropic/v1/models": {
      "get": {
        "tags": [
          "AI Gateway"
        ],
        "summary": "List models",
        "operationId": "anthropicListModels",
        "responses": {
          "200": {
            "description": "Models"
          }
        }
      }
    },
    "/ai/anthropic/v1/models/{model}": {
      "get": {
        "tags": [
          "AI Gateway"
        ],
        "summary": "Retrieve a model",
        "operationId": "anthropicGetModel",
        "parameters": [
          {
            "name": "model",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Model"
          },
          "404": {
            "description": "not_found_error"
          }
        }
      }
    },
    "/ai/gemini/v1beta/models": {
      "get": {
        "tags": [
          "AI Gateway"
        ],
        "summary": "Gemini: list models",
        "operationId": "geminiListModels",
        "responses": {
          "200": {
            "description": "Models"
          }
        }
      }
    },
    "/ai/gemini/v1beta/models/{rest}": {
      "get": {
        "tags": [
          "AI Gateway"
        ],
        "summary": "Gemini: get a model",
        "operationId": "geminiGetModel",
        "parameters": [
          {
            "name": "rest",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Model"
          }
        }
      },
      "post": {
        "tags": [
          "AI Gateway"
        ],
        "summary": "Gemini: generateContent / streamGenerateContent / countTokens / embedContent / batchEmbedContents",
        "operationId": "geminiAction",
        "parameters": [
          {
            "name": "rest",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "{model}:{action}, e.g. gemini-2.5-flash:generateContent"
          },
          {
            "name": "alt",
            "in": "query",
            "schema": {
              "type": "string",
              "enum": [
                "sse"
              ]
            }
          },
          {
            "name": "key",
            "in": "query",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "x-goog-api-key",
            "in": "header",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "X-Rustybin-Mode",
            "in": "header",
            "schema": {
              "type": "string",
              "enum": [
                "canned",
                "echo",
                "scripted",
                "random"
              ]
            },
            "description": "Reply mode (also selectable by a model name segment, e.g. rustybin-echo)"
          },
          {
            "name": "X-Rustybin-Latency-Ms",
            "in": "header",
            "schema": {
              "type": "integer"
            },
            "description": "Delay before response headers"
          },
          {
            "name": "X-Rustybin-TTFT-Ms",
            "in": "header",
            "schema": {
              "type": "integer"
            },
            "description": "Time to first token"
          },
          {
            "name": "X-Rustybin-Tokens-Per-Second",
            "in": "header",
            "schema": {
              "type": "integer"
            },
            "description": "Streaming pace (default 100, 0 = unpaced)"
          },
          {
            "name": "X-Rustybin-Fail",
            "in": "header",
            "schema": {
              "type": "string"
            },
            "description": "kind[:percent]: 429, 500, 503, 529, 504, context_length, content_filter, prompt_filter, 401, ... in the provider's native error shape"
          },
          {
            "name": "X-Rustybin-Require-Auth",
            "in": "header",
            "schema": {
              "type": "boolean"
            },
            "description": "Enforce the provider's native credential"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "contents": {
                    "type": "array",
                    "items": {
                      "type": "object",
                      "properties": {
                        "role": {
                          "type": "string",
                          "enum": [
                            "user",
                            "model"
                          ]
                        },
                        "parts": {
                          "type": "array",
                          "items": {
                            "type": "object"
                          }
                        }
                      }
                    }
                  },
                  "systemInstruction": {
                    "type": "object"
                  },
                  "tools": {
                    "type": "array",
                    "items": {
                      "type": "object"
                    }
                  },
                  "toolConfig": {
                    "type": "object"
                  },
                  "generationConfig": {
                    "type": "object",
                    "properties": {
                      "maxOutputTokens": {
                        "type": "integer"
                      },
                      "responseMimeType": {
                        "type": "string"
                      },
                      "responseSchema": {
                        "type": "object"
                      },
                      "candidateCount": {
                        "type": "integer"
                      },
                      "stopSequences": {
                        "type": "array",
                        "items": {
                          "type": "string"
                        }
                      }
                    }
                  },
                  "content": {
                    "type": "object",
                    "description": "embedContent"
                  },
                  "requests": {
                    "type": "array",
                    "items": {
                      "type": "object"
                    },
                    "description": "batchEmbedContents"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "GenerateContentResponse (candidates, usageMetadata), SSE chunks, token count or embedding"
          },
          "400": {
            "description": "INVALID_ARGUMENT"
          },
          "403": {
            "description": "PERMISSION_DENIED (missing key, when required)"
          },
          "429": {
            "description": "RESOURCE_EXHAUSTED (simulated)"
          }
        }
      }
    },
    "/ai/bedrock/model/{model_id}/converse": {
      "post": {
        "tags": [
          "AI Gateway"
        ],
        "summary": "Bedrock Converse",
        "operationId": "bedrockConverse",
        "parameters": [
          {
            "name": "model_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "example": "anthropic.claude-3-5-sonnet-20240620-v1:0"
          },
          {
            "name": "Authorization",
            "in": "header",
            "schema": {
              "type": "string"
            },
            "description": "AWS4-HMAC-SHA256 Credential=AKID/yyyymmdd/region/bedrock/aws4_request, SignedHeaders=..., Signature=..."
          },
          {
            "name": "X-Amz-Date",
            "in": "header",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "X-Rustybin-Mode",
            "in": "header",
            "schema": {
              "type": "string",
              "enum": [
                "canned",
                "echo",
                "scripted",
                "random"
              ]
            },
            "description": "Reply mode (also selectable by a model name segment, e.g. rustybin-echo)"
          },
          {
            "name": "X-Rustybin-Latency-Ms",
            "in": "header",
            "schema": {
              "type": "integer"
            },
            "description": "Delay before response headers"
          },
          {
            "name": "X-Rustybin-TTFT-Ms",
            "in": "header",
            "schema": {
              "type": "integer"
            },
            "description": "Time to first token"
          },
          {
            "name": "X-Rustybin-Tokens-Per-Second",
            "in": "header",
            "schema": {
              "type": "integer"
            },
            "description": "Streaming pace (default 100, 0 = unpaced)"
          },
          {
            "name": "X-Rustybin-Fail",
            "in": "header",
            "schema": {
              "type": "string"
            },
            "description": "kind[:percent]: 429, 500, 503, 529, 504, context_length, content_filter, prompt_filter, 401, ... in the provider's native error shape"
          },
          {
            "name": "X-Rustybin-Require-Auth",
            "in": "header",
            "schema": {
              "type": "boolean"
            },
            "description": "Enforce the provider's native credential"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "messages": {
                    "type": "array",
                    "items": {
                      "type": "object"
                    }
                  },
                  "system": {
                    "type": "array",
                    "items": {
                      "type": "object"
                    }
                  },
                  "inferenceConfig": {
                    "type": "object"
                  },
                  "toolConfig": {
                    "type": "object"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "400": {
            "description": "ValidationException"
          },
          "403": {
            "description": "MissingAuthenticationTokenException / IncompleteSignatureException (when required)"
          },
          "429": {
            "description": "ThrottlingException (simulated)"
          }
        }
      }
    },
    "/ai/bedrock/model/{model_id}/converse-stream": {
      "post": {
        "tags": [
          "AI Gateway"
        ],
        "summary": "Bedrock ConverseStream",
        "operationId": "bedrockConverseStream",
        "parameters": [
          {
            "name": "model_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "example": "anthropic.claude-3-5-sonnet-20240620-v1:0"
          },
          {
            "name": "Authorization",
            "in": "header",
            "schema": {
              "type": "string"
            },
            "description": "AWS4-HMAC-SHA256 Credential=AKID/yyyymmdd/region/bedrock/aws4_request, SignedHeaders=..., Signature=..."
          },
          {
            "name": "X-Amz-Date",
            "in": "header",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "X-Rustybin-Mode",
            "in": "header",
            "schema": {
              "type": "string",
              "enum": [
                "canned",
                "echo",
                "scripted",
                "random"
              ]
            },
            "description": "Reply mode (also selectable by a model name segment, e.g. rustybin-echo)"
          },
          {
            "name": "X-Rustybin-Latency-Ms",
            "in": "header",
            "schema": {
              "type": "integer"
            },
            "description": "Delay before response headers"
          },
          {
            "name": "X-Rustybin-TTFT-Ms",
            "in": "header",
            "schema": {
              "type": "integer"
            },
            "description": "Time to first token"
          },
          {
            "name": "X-Rustybin-Tokens-Per-Second",
            "in": "header",
            "schema": {
              "type": "integer"
            },
            "description": "Streaming pace (default 100, 0 = unpaced)"
          },
          {
            "name": "X-Rustybin-Fail",
            "in": "header",
            "schema": {
              "type": "string"
            },
            "description": "kind[:percent]: 429, 500, 503, 529, 504, context_length, content_filter, prompt_filter, 401, ... in the provider's native error shape"
          },
          {
            "name": "X-Rustybin-Require-Auth",
            "in": "header",
            "schema": {
              "type": "boolean"
            },
            "description": "Enforce the provider's native credential"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "messages": {
                    "type": "array",
                    "items": {
                      "type": "object"
                    }
                  },
                  "system": {
                    "type": "array",
                    "items": {
                      "type": "object"
                    }
                  },
                  "inferenceConfig": {
                    "type": "object"
                  },
                  "toolConfig": {
                    "type": "object"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/vnd.amazon.eventstream": {
                "schema": {
                  "type": "string",
                  "format": "binary"
                }
              }
            }
          },
          "400": {
            "description": "ValidationException"
          },
          "403": {
            "description": "MissingAuthenticationTokenException / IncompleteSignatureException (when required)"
          },
          "429": {
            "description": "ThrottlingException (simulated)"
          }
        }
      }
    },
    "/ai/bedrock/model/{model_id}/invoke": {
      "post": {
        "tags": [
          "AI Gateway"
        ],
        "summary": "Bedrock InvokeModel",
        "operationId": "bedrockInvoke",
        "parameters": [
          {
            "name": "model_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "example": "anthropic.claude-3-5-sonnet-20240620-v1:0"
          },
          {
            "name": "Authorization",
            "in": "header",
            "schema": {
              "type": "string"
            },
            "description": "AWS4-HMAC-SHA256 Credential=AKID/yyyymmdd/region/bedrock/aws4_request, SignedHeaders=..., Signature=..."
          },
          {
            "name": "X-Amz-Date",
            "in": "header",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "X-Rustybin-Mode",
            "in": "header",
            "schema": {
              "type": "string",
              "enum": [
                "canned",
                "echo",
                "scripted",
                "random"
              ]
            },
            "description": "Reply mode (also selectable by a model name segment, e.g. rustybin-echo)"
          },
          {
            "name": "X-Rustybin-Latency-Ms",
            "in": "header",
            "schema": {
              "type": "integer"
            },
            "description": "Delay before response headers"
          },
          {
            "name": "X-Rustybin-TTFT-Ms",
            "in": "header",
            "schema": {
              "type": "integer"
            },
            "description": "Time to first token"
          },
          {
            "name": "X-Rustybin-Tokens-Per-Second",
            "in": "header",
            "schema": {
              "type": "integer"
            },
            "description": "Streaming pace (default 100, 0 = unpaced)"
          },
          {
            "name": "X-Rustybin-Fail",
            "in": "header",
            "schema": {
              "type": "string"
            },
            "description": "kind[:percent]: 429, 500, 503, 529, 504, context_length, content_filter, prompt_filter, 401, ... in the provider's native error shape"
          },
          {
            "name": "X-Rustybin-Require-Auth",
            "in": "header",
            "schema": {
              "type": "boolean"
            },
            "description": "Enforce the provider's native credential"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "messages": {
                    "type": "array",
                    "items": {
                      "type": "object"
                    }
                  },
                  "system": {
                    "type": "array",
                    "items": {
                      "type": "object"
                    }
                  },
                  "inferenceConfig": {
                    "type": "object"
                  },
                  "toolConfig": {
                    "type": "object"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "400": {
            "description": "ValidationException"
          },
          "403": {
            "description": "MissingAuthenticationTokenException / IncompleteSignatureException (when required)"
          },
          "429": {
            "description": "ThrottlingException (simulated)"
          }
        }
      }
    },
    "/ai/bedrock/model/{model_id}/invoke-with-response-stream": {
      "post": {
        "tags": [
          "AI Gateway"
        ],
        "summary": "Bedrock InvokeModelWithResponseStream",
        "operationId": "bedrockInvokeStream",
        "parameters": [
          {
            "name": "model_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "example": "anthropic.claude-3-5-sonnet-20240620-v1:0"
          },
          {
            "name": "Authorization",
            "in": "header",
            "schema": {
              "type": "string"
            },
            "description": "AWS4-HMAC-SHA256 Credential=AKID/yyyymmdd/region/bedrock/aws4_request, SignedHeaders=..., Signature=..."
          },
          {
            "name": "X-Amz-Date",
            "in": "header",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "X-Rustybin-Mode",
            "in": "header",
            "schema": {
              "type": "string",
              "enum": [
                "canned",
                "echo",
                "scripted",
                "random"
              ]
            },
            "description": "Reply mode (also selectable by a model name segment, e.g. rustybin-echo)"
          },
          {
            "name": "X-Rustybin-Latency-Ms",
            "in": "header",
            "schema": {
              "type": "integer"
            },
            "description": "Delay before response headers"
          },
          {
            "name": "X-Rustybin-TTFT-Ms",
            "in": "header",
            "schema": {
              "type": "integer"
            },
            "description": "Time to first token"
          },
          {
            "name": "X-Rustybin-Tokens-Per-Second",
            "in": "header",
            "schema": {
              "type": "integer"
            },
            "description": "Streaming pace (default 100, 0 = unpaced)"
          },
          {
            "name": "X-Rustybin-Fail",
            "in": "header",
            "schema": {
              "type": "string"
            },
            "description": "kind[:percent]: 429, 500, 503, 529, 504, context_length, content_filter, prompt_filter, 401, ... in the provider's native error shape"
          },
          {
            "name": "X-Rustybin-Require-Auth",
            "in": "header",
            "schema": {
              "type": "boolean"
            },
            "description": "Enforce the provider's native credential"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "messages": {
                    "type": "array",
                    "items": {
                      "type": "object"
                    }
                  },
                  "system": {
                    "type": "array",
                    "items": {
                      "type": "object"
                    }
                  },
                  "inferenceConfig": {
                    "type": "object"
                  },
                  "toolConfig": {
                    "type": "object"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/vnd.amazon.eventstream": {
                "schema": {
                  "type": "string",
                  "format": "binary"
                }
              }
            }
          },
          "400": {
            "description": "ValidationException"
          },
          "403": {
            "description": "MissingAuthenticationTokenException / IncompleteSignatureException (when required)"
          },
          "429": {
            "description": "ThrottlingException (simulated)"
          }
        }
      }
    },
    "/ai/ollama/api/chat": {
      "post": {
        "tags": [
          "AI Gateway"
        ],
        "summary": "Ollama chat",
        "operationId": "ollamaChat",
        "parameters": [
          {
            "name": "X-Rustybin-Mode",
            "in": "header",
            "schema": {
              "type": "string",
              "enum": [
                "canned",
                "echo",
                "scripted",
                "random"
              ]
            },
            "description": "Reply mode (also selectable by a model name segment, e.g. rustybin-echo)"
          },
          {
            "name": "X-Rustybin-Latency-Ms",
            "in": "header",
            "schema": {
              "type": "integer"
            },
            "description": "Delay before response headers"
          },
          {
            "name": "X-Rustybin-TTFT-Ms",
            "in": "header",
            "schema": {
              "type": "integer"
            },
            "description": "Time to first token"
          },
          {
            "name": "X-Rustybin-Tokens-Per-Second",
            "in": "header",
            "schema": {
              "type": "integer"
            },
            "description": "Streaming pace (default 100, 0 = unpaced)"
          },
          {
            "name": "X-Rustybin-Fail",
            "in": "header",
            "schema": {
              "type": "string"
            },
            "description": "kind[:percent]: 429, 500, 503, 529, 504, context_length, content_filter, prompt_filter, 401, ... in the provider's native error shape"
          },
          {
            "name": "X-Rustybin-Require-Auth",
            "in": "header",
            "schema": {
              "type": "boolean"
            },
            "description": "Enforce the provider's native credential"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "model": {
                    "type": "string"
                  },
                  "messages": {
                    "type": "array",
                    "items": {
                      "type": "object"
                    }
                  },
                  "prompt": {
                    "type": "string"
                  },
                  "input": {},
                  "stream": {
                    "type": "boolean",
                    "default": true
                  },
                  "format": {},
                  "options": {
                    "type": "object"
                  },
                  "tools": {
                    "type": "array",
                    "items": {
                      "type": "object"
                    }
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/x-ndjson": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "400": {
            "description": "{\"error\": ...}"
          }
        }
      }
    },
    "/ai/ollama/api/generate": {
      "post": {
        "tags": [
          "AI Gateway"
        ],
        "summary": "Ollama generate",
        "operationId": "ollamaGenerate",
        "parameters": [
          {
            "name": "X-Rustybin-Mode",
            "in": "header",
            "schema": {
              "type": "string",
              "enum": [
                "canned",
                "echo",
                "scripted",
                "random"
              ]
            },
            "description": "Reply mode (also selectable by a model name segment, e.g. rustybin-echo)"
          },
          {
            "name": "X-Rustybin-Latency-Ms",
            "in": "header",
            "schema": {
              "type": "integer"
            },
            "description": "Delay before response headers"
          },
          {
            "name": "X-Rustybin-TTFT-Ms",
            "in": "header",
            "schema": {
              "type": "integer"
            },
            "description": "Time to first token"
          },
          {
            "name": "X-Rustybin-Tokens-Per-Second",
            "in": "header",
            "schema": {
              "type": "integer"
            },
            "description": "Streaming pace (default 100, 0 = unpaced)"
          },
          {
            "name": "X-Rustybin-Fail",
            "in": "header",
            "schema": {
              "type": "string"
            },
            "description": "kind[:percent]: 429, 500, 503, 529, 504, context_length, content_filter, prompt_filter, 401, ... in the provider's native error shape"
          },
          {
            "name": "X-Rustybin-Require-Auth",
            "in": "header",
            "schema": {
              "type": "boolean"
            },
            "description": "Enforce the provider's native credential"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "model": {
                    "type": "string"
                  },
                  "messages": {
                    "type": "array",
                    "items": {
                      "type": "object"
                    }
                  },
                  "prompt": {
                    "type": "string"
                  },
                  "input": {},
                  "stream": {
                    "type": "boolean",
                    "default": true
                  },
                  "format": {},
                  "options": {
                    "type": "object"
                  },
                  "tools": {
                    "type": "array",
                    "items": {
                      "type": "object"
                    }
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/x-ndjson": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "400": {
            "description": "{\"error\": ...}"
          }
        }
      }
    },
    "/ai/ollama/api/embed": {
      "post": {
        "tags": [
          "AI Gateway"
        ],
        "summary": "Ollama embed",
        "operationId": "ollamaEmbed",
        "parameters": [
          {
            "name": "X-Rustybin-Mode",
            "in": "header",
            "schema": {
              "type": "string",
              "enum": [
                "canned",
                "echo",
                "scripted",
                "random"
              ]
            },
            "description": "Reply mode (also selectable by a model name segment, e.g. rustybin-echo)"
          },
          {
            "name": "X-Rustybin-Latency-Ms",
            "in": "header",
            "schema": {
              "type": "integer"
            },
            "description": "Delay before response headers"
          },
          {
            "name": "X-Rustybin-TTFT-Ms",
            "in": "header",
            "schema": {
              "type": "integer"
            },
            "description": "Time to first token"
          },
          {
            "name": "X-Rustybin-Tokens-Per-Second",
            "in": "header",
            "schema": {
              "type": "integer"
            },
            "description": "Streaming pace (default 100, 0 = unpaced)"
          },
          {
            "name": "X-Rustybin-Fail",
            "in": "header",
            "schema": {
              "type": "string"
            },
            "description": "kind[:percent]: 429, 500, 503, 529, 504, context_length, content_filter, prompt_filter, 401, ... in the provider's native error shape"
          },
          {
            "name": "X-Rustybin-Require-Auth",
            "in": "header",
            "schema": {
              "type": "boolean"
            },
            "description": "Enforce the provider's native credential"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "model": {
                    "type": "string"
                  },
                  "messages": {
                    "type": "array",
                    "items": {
                      "type": "object"
                    }
                  },
                  "prompt": {
                    "type": "string"
                  },
                  "input": {},
                  "stream": {
                    "type": "boolean",
                    "default": true
                  },
                  "format": {},
                  "options": {
                    "type": "object"
                  },
                  "tools": {
                    "type": "array",
                    "items": {
                      "type": "object"
                    }
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "400": {
            "description": "{\"error\": ...}"
          }
        }
      }
    },
    "/ai/ollama/api/embeddings": {
      "post": {
        "tags": [
          "AI Gateway"
        ],
        "summary": "Ollama legacy embeddings",
        "operationId": "ollamaEmbeddings",
        "parameters": [
          {
            "name": "X-Rustybin-Mode",
            "in": "header",
            "schema": {
              "type": "string",
              "enum": [
                "canned",
                "echo",
                "scripted",
                "random"
              ]
            },
            "description": "Reply mode (also selectable by a model name segment, e.g. rustybin-echo)"
          },
          {
            "name": "X-Rustybin-Latency-Ms",
            "in": "header",
            "schema": {
              "type": "integer"
            },
            "description": "Delay before response headers"
          },
          {
            "name": "X-Rustybin-TTFT-Ms",
            "in": "header",
            "schema": {
              "type": "integer"
            },
            "description": "Time to first token"
          },
          {
            "name": "X-Rustybin-Tokens-Per-Second",
            "in": "header",
            "schema": {
              "type": "integer"
            },
            "description": "Streaming pace (default 100, 0 = unpaced)"
          },
          {
            "name": "X-Rustybin-Fail",
            "in": "header",
            "schema": {
              "type": "string"
            },
            "description": "kind[:percent]: 429, 500, 503, 529, 504, context_length, content_filter, prompt_filter, 401, ... in the provider's native error shape"
          },
          {
            "name": "X-Rustybin-Require-Auth",
            "in": "header",
            "schema": {
              "type": "boolean"
            },
            "description": "Enforce the provider's native credential"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "model": {
                    "type": "string"
                  },
                  "messages": {
                    "type": "array",
                    "items": {
                      "type": "object"
                    }
                  },
                  "prompt": {
                    "type": "string"
                  },
                  "input": {},
                  "stream": {
                    "type": "boolean",
                    "default": true
                  },
                  "format": {},
                  "options": {
                    "type": "object"
                  },
                  "tools": {
                    "type": "array",
                    "items": {
                      "type": "object"
                    }
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "400": {
            "description": "{\"error\": ...}"
          }
        }
      }
    },
    "/ai/ollama/api/tags": {
      "get": {
        "tags": [
          "AI Gateway"
        ],
        "summary": "Ollama tags",
        "operationId": "ollamaTags",
        "responses": {
          "200": {
            "description": "Models"
          }
        }
      }
    },
    "/ai/cohere/v2/rerank": {
      "post": {
        "tags": [
          "AI Gateway"
        ],
        "summary": "Rerank documents",
        "operationId": "cohereRerank",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "query",
                  "documents"
                ],
                "properties": {
                  "model": {
                    "type": "string"
                  },
                  "query": {
                    "type": "string"
                  },
                  "documents": {
                    "type": "array",
                    "items": {}
                  },
                  "top_n": {
                    "type": "integer"
                  },
                  "return_documents": {
                    "type": "boolean"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Results sorted by relevance",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "results": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "index": {
                            "type": "integer"
                          },
                          "relevance_score": {
                            "type": "number"
                          }
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Invalid request"
          }
        }
      }
    },
    "/ai/v1/rerank": {
      "post": {
        "tags": [
          "AI Gateway"
        ],
        "summary": "Rerank documents",
        "operationId": "rerank",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "query",
                  "documents"
                ],
                "properties": {
                  "model": {
                    "type": "string"
                  },
                  "query": {
                    "type": "string"
                  },
                  "documents": {
                    "type": "array",
                    "items": {}
                  },
                  "top_n": {
                    "type": "integer"
                  },
                  "return_documents": {
                    "type": "boolean"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Results sorted by relevance",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "results": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "index": {
                            "type": "integer"
                          },
                          "relevance_score": {
                            "type": "number"
                          }
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Invalid request"
          }
        }
      }
    },
    "/ai/cohere/v2/embed": {
      "post": {
        "tags": [
          "AI Gateway"
        ],
        "summary": "Cohere embed",
        "operationId": "cohereEmbed",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "model": {
                    "type": "string"
                  },
                  "texts": {
                    "type": "array",
                    "items": {
                      "type": "string"
                    }
                  },
                  "input_type": {
                    "type": "string"
                  },
                  "embedding_types": {
                    "type": "array",
                    "items": {
                      "type": "string"
                    }
                  },
                  "output_dimension": {
                    "type": "integer"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Embeddings by type"
          },
          "400": {
            "description": "Invalid request"
          }
        }
      }
    },
    "/ai/requests": {
      "get": {
        "tags": [
          "AI Gateway"
        ],
        "summary": "Recent mock LLM exchanges",
        "operationId": "aiListRequests",
        "parameters": [
          {
            "name": "limit",
            "in": "query",
            "schema": {
              "type": "integer",
              "maximum": 200
            }
          },
          {
            "name": "session",
            "in": "query",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Summaries, newest first"
          }
        }
      }
    },
    "/ai/requests/{id}": {
      "get": {
        "tags": [
          "AI Gateway"
        ],
        "summary": "What the upstream received for one AI request",
        "operationId": "aiGetRequest",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "X-Rustybin-Request-Id of the AI response"
          },
          {
            "name": "session",
            "in": "query",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Recorded exchange",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AiRequestRecord"
                }
              }
            }
          },
          "404": {
            "description": "Unknown or expired id (or another session's request in public mode)"
          }
        }
      }
    },
    "/graphql/ws": {
      "get": {
        "tags": [
          "GraphQL"
        ],
        "summary": "GraphQL subscriptions over WebSocket",
        "description": "WebSocket upgrade with Sec-WebSocket-Protocol graphql-transport-ws (graphql-ws library) or graphql-ws (legacy subscriptions-transport-ws). Subscriptions: ticker(count, intervalMs), orderUpdates(orderId, intervalMs).",
        "operationId": "graphqlSubscriptions",
        "parameters": [
          {
            "name": "Sec-WebSocket-Protocol",
            "in": "header",
            "required": true,
            "schema": {
              "type": "string",
              "enum": [
                "graphql-transport-ws",
                "graphql-ws"
              ]
            }
          }
        ],
        "responses": {
          "101": {
            "description": "Switching Protocols"
          },
          "400": {
            "description": "Missing or unsupported subprotocol"
          }
        }
      }
    },
    "/.well-known/agent-card.json": {
      "get": {
        "tags": [
          "A2A Agents"
        ],
        "summary": "A2A Agent Card (default agent)",
        "operationId": "a2aAgentCard",
        "description": "v1.0 card with supportedInterfaces plus the v0.3 url/preferredTransport fields; lists all demo agents in capabilities.extensions",
        "parameters": [
          {
            "name": "A2A-Version",
            "in": "header",
            "required": false,
            "schema": {
              "type": "string",
              "enum": [
                "1.0",
                "0.3"
              ]
            },
            "description": "Protocol version; empty means 0.3"
          }
        ],
        "responses": {
          "200": {
            "description": "A2A response",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          }
        }
      }
    },
    "/.well-known/agent.json": {
      "get": {
        "tags": [
          "A2A Agents"
        ],
        "summary": "Legacy A2A v0.3 Agent Card",
        "operationId": "a2aLegacyAgentCard",
        "description": "v0.3 card of the default agent",
        "parameters": [
          {
            "name": "A2A-Version",
            "in": "header",
            "required": false,
            "schema": {
              "type": "string",
              "enum": [
                "1.0",
                "0.3"
              ]
            },
            "description": "Protocol version; empty means 0.3"
          }
        ],
        "responses": {
          "200": {
            "description": "A2A response",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          }
        }
      }
    },
    "/a2a": {
      "get": {
        "tags": [
          "A2A Agents"
        ],
        "summary": "A2A agent directory",
        "operationId": "a2aDirectory",
        "description": "Lists the demo agents and their endpoints",
        "parameters": [
          {
            "name": "A2A-Version",
            "in": "header",
            "required": false,
            "schema": {
              "type": "string",
              "enum": [
                "1.0",
                "0.3"
              ]
            },
            "description": "Protocol version; empty means 0.3"
          }
        ],
        "responses": {
          "200": {
            "description": "A2A response",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          }
        }
      },
      "post": {
        "tags": [
          "A2A Agents"
        ],
        "summary": "A2A JSON-RPC (default echo agent)",
        "operationId": "a2aJsonRpcDefault",
        "description": "JSON-RPC 2.0. v1.0 methods (A2A-Version: 1.0): SendMessage, SendStreamingMessage (SSE), GetTask, ListTasks, CancelTask, SubscribeToTask (SSE), Create/Get/List/DeleteTaskPushNotificationConfig, GetExtendedAgentCard. v0.3 methods (no header): message/send, message/stream, tasks/get, tasks/cancel, tasks/resubscribe, tasks/pushNotificationConfig/set|get|list|delete, agent/getAuthenticatedExtendedCard.",
        "parameters": [
          {
            "name": "A2A-Version",
            "in": "header",
            "required": false,
            "schema": {
              "type": "string",
              "enum": [
                "1.0",
                "0.3"
              ]
            },
            "description": "Protocol version; empty means 0.3"
          }
        ],
        "responses": {
          "200": {
            "description": "A2A response",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object"
              }
            }
          }
        }
      }
    },
    "/a2a/{agent}": {
      "get": {
        "tags": [
          "A2A Agents"
        ],
        "summary": "A2A Agent Card of an agent",
        "operationId": "a2aAgentCardByAgent",
        "description": "Same as /a2a/{agent}/.well-known/agent-card.json",
        "parameters": [
          {
            "name": "A2A-Version",
            "in": "header",
            "required": false,
            "schema": {
              "type": "string",
              "enum": [
                "1.0",
                "0.3"
              ]
            },
            "description": "Protocol version; empty means 0.3"
          },
          {
            "name": "agent",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "enum": [
                "echo",
                "weather",
                "travel-planner",
                "approval",
                "flaky",
                "secure",
                "reject"
              ]
            }
          }
        ],
        "responses": {
          "200": {
            "description": "A2A response",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          }
        }
      },
      "post": {
        "tags": [
          "A2A Agents"
        ],
        "summary": "A2A JSON-RPC endpoint",
        "operationId": "a2aJsonRpc",
        "description": "JSON-RPC 2.0. v1.0 methods (A2A-Version: 1.0): SendMessage, SendStreamingMessage (SSE), GetTask, ListTasks, CancelTask, SubscribeToTask (SSE), Create/Get/List/DeleteTaskPushNotificationConfig, GetExtendedAgentCard. v0.3 methods (no header): message/send, message/stream, tasks/get, tasks/cancel, tasks/resubscribe, tasks/pushNotificationConfig/set|get|list|delete, agent/getAuthenticatedExtendedCard.",
        "parameters": [
          {
            "name": "A2A-Version",
            "in": "header",
            "required": false,
            "schema": {
              "type": "string",
              "enum": [
                "1.0",
                "0.3"
              ]
            },
            "description": "Protocol version; empty means 0.3"
          },
          {
            "name": "agent",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "enum": [
                "echo",
                "weather",
                "travel-planner",
                "approval",
                "flaky",
                "secure",
                "reject"
              ]
            }
          }
        ],
        "responses": {
          "200": {
            "description": "A2A response",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object"
              }
            }
          }
        }
      }
    },
    "/a2a/{agent}/.well-known/agent-card.json": {
      "get": {
        "tags": [
          "A2A Agents"
        ],
        "summary": "A2A Agent Card of an agent",
        "operationId": "a2aAgentCardWellKnown",
        "description": "v1.0 card plus v0.3 fields",
        "parameters": [
          {
            "name": "A2A-Version",
            "in": "header",
            "required": false,
            "schema": {
              "type": "string",
              "enum": [
                "1.0",
                "0.3"
              ]
            },
            "description": "Protocol version; empty means 0.3"
          },
          {
            "name": "agent",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "enum": [
                "echo",
                "weather",
                "travel-planner",
                "approval",
                "flaky",
                "secure",
                "reject"
              ]
            }
          }
        ],
        "responses": {
          "200": {
            "description": "A2A response",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          }
        }
      }
    },
    "/a2a/{agent}/.well-known/agent.json": {
      "get": {
        "tags": [
          "A2A Agents"
        ],
        "summary": "Legacy v0.3 Agent Card of an agent",
        "operationId": "a2aLegacyAgentCardByAgent",
        "description": "v0.3 card",
        "parameters": [
          {
            "name": "A2A-Version",
            "in": "header",
            "required": false,
            "schema": {
              "type": "string",
              "enum": [
                "1.0",
                "0.3"
              ]
            },
            "description": "Protocol version; empty means 0.3"
          },
          {
            "name": "agent",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "enum": [
                "echo",
                "weather",
                "travel-planner",
                "approval",
                "flaky",
                "secure",
                "reject"
              ]
            }
          }
        ],
        "responses": {
          "200": {
            "description": "A2A response",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          }
        }
      }
    },
    "/a2a/{agent}/v1/{rest}": {
      "get": {
        "tags": [
          "A2A Agents"
        ],
        "summary": "A2A REST binding (get)",
        "operationId": "a2aRestget",
        "description": "HTTP+JSON binding. v1.0: POST message:send, POST message:stream (SSE), GET tasks, GET tasks/{id}, POST tasks/{id}:cancel, GET|POST tasks/{id}:subscribe (SSE), POST|GET tasks/{id}/pushNotificationConfigs, GET|DELETE tasks/{id}/pushNotificationConfigs/{configId}, GET extendedAgentCard. v0.3 (no header): same paths with v0.3 ProtoJSON plus GET card.",
        "parameters": [
          {
            "name": "A2A-Version",
            "in": "header",
            "required": false,
            "schema": {
              "type": "string",
              "enum": [
                "1.0",
                "0.3"
              ]
            },
            "description": "Protocol version; empty means 0.3"
          },
          {
            "name": "agent",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "enum": [
                "echo",
                "weather",
                "travel-planner",
                "approval",
                "flaky",
                "secure",
                "reject"
              ]
            }
          },
          {
            "name": "rest",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Binding path, e.g. message:send or tasks/{id}:cancel"
          }
        ],
        "responses": {
          "200": {
            "description": "A2A response",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          }
        }
      },
      "post": {
        "tags": [
          "A2A Agents"
        ],
        "summary": "A2A REST binding (post)",
        "operationId": "a2aRestpost",
        "description": "HTTP+JSON binding. v1.0: POST message:send, POST message:stream (SSE), GET tasks, GET tasks/{id}, POST tasks/{id}:cancel, GET|POST tasks/{id}:subscribe (SSE), POST|GET tasks/{id}/pushNotificationConfigs, GET|DELETE tasks/{id}/pushNotificationConfigs/{configId}, GET extendedAgentCard. v0.3 (no header): same paths with v0.3 ProtoJSON plus GET card.",
        "parameters": [
          {
            "name": "A2A-Version",
            "in": "header",
            "required": false,
            "schema": {
              "type": "string",
              "enum": [
                "1.0",
                "0.3"
              ]
            },
            "description": "Protocol version; empty means 0.3"
          },
          {
            "name": "agent",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "enum": [
                "echo",
                "weather",
                "travel-planner",
                "approval",
                "flaky",
                "secure",
                "reject"
              ]
            }
          },
          {
            "name": "rest",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Binding path, e.g. message:send or tasks/{id}:cancel"
          }
        ],
        "responses": {
          "200": {
            "description": "A2A response",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object"
              }
            }
          }
        }
      },
      "put": {
        "tags": [
          "A2A Agents"
        ],
        "summary": "A2A REST binding (put)",
        "operationId": "a2aRestput",
        "description": "HTTP+JSON binding. v1.0: POST message:send, POST message:stream (SSE), GET tasks, GET tasks/{id}, POST tasks/{id}:cancel, GET|POST tasks/{id}:subscribe (SSE), POST|GET tasks/{id}/pushNotificationConfigs, GET|DELETE tasks/{id}/pushNotificationConfigs/{configId}, GET extendedAgentCard. v0.3 (no header): same paths with v0.3 ProtoJSON plus GET card.",
        "parameters": [
          {
            "name": "A2A-Version",
            "in": "header",
            "required": false,
            "schema": {
              "type": "string",
              "enum": [
                "1.0",
                "0.3"
              ]
            },
            "description": "Protocol version; empty means 0.3"
          },
          {
            "name": "agent",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "enum": [
                "echo",
                "weather",
                "travel-planner",
                "approval",
                "flaky",
                "secure",
                "reject"
              ]
            }
          },
          {
            "name": "rest",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Binding path, e.g. message:send or tasks/{id}:cancel"
          }
        ],
        "responses": {
          "200": {
            "description": "A2A response",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          }
        }
      },
      "patch": {
        "tags": [
          "A2A Agents"
        ],
        "summary": "A2A REST binding (patch)",
        "operationId": "a2aRestpatch",
        "description": "HTTP+JSON binding. v1.0: POST message:send, POST message:stream (SSE), GET tasks, GET tasks/{id}, POST tasks/{id}:cancel, GET|POST tasks/{id}:subscribe (SSE), POST|GET tasks/{id}/pushNotificationConfigs, GET|DELETE tasks/{id}/pushNotificationConfigs/{configId}, GET extendedAgentCard. v0.3 (no header): same paths with v0.3 ProtoJSON plus GET card.",
        "parameters": [
          {
            "name": "A2A-Version",
            "in": "header",
            "required": false,
            "schema": {
              "type": "string",
              "enum": [
                "1.0",
                "0.3"
              ]
            },
            "description": "Protocol version; empty means 0.3"
          },
          {
            "name": "agent",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "enum": [
                "echo",
                "weather",
                "travel-planner",
                "approval",
                "flaky",
                "secure",
                "reject"
              ]
            }
          },
          {
            "name": "rest",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Binding path, e.g. message:send or tasks/{id}:cancel"
          }
        ],
        "responses": {
          "200": {
            "description": "A2A response",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          }
        }
      },
      "delete": {
        "tags": [
          "A2A Agents"
        ],
        "summary": "A2A REST binding (delete)",
        "operationId": "a2aRestdelete",
        "description": "HTTP+JSON binding. v1.0: POST message:send, POST message:stream (SSE), GET tasks, GET tasks/{id}, POST tasks/{id}:cancel, GET|POST tasks/{id}:subscribe (SSE), POST|GET tasks/{id}/pushNotificationConfigs, GET|DELETE tasks/{id}/pushNotificationConfigs/{configId}, GET extendedAgentCard. v0.3 (no header): same paths with v0.3 ProtoJSON plus GET card.",
        "parameters": [
          {
            "name": "A2A-Version",
            "in": "header",
            "required": false,
            "schema": {
              "type": "string",
              "enum": [
                "1.0",
                "0.3"
              ]
            },
            "description": "Protocol version; empty means 0.3"
          },
          {
            "name": "agent",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "enum": [
                "echo",
                "weather",
                "travel-planner",
                "approval",
                "flaky",
                "secure",
                "reject"
              ]
            }
          },
          {
            "name": "rest",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Binding path, e.g. message:send or tasks/{id}:cancel"
          }
        ],
        "responses": {
          "200": {
            "description": "A2A response",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          }
        }
      }
    },
    "/a2a/{agent}/v1/message:send": {
      "post": {
        "tags": [
          "A2A Agents"
        ],
        "summary": "REST SendMessage",
        "operationId": "a2aRestSendMessage",
        "description": "HTTP+JSON binding. v1.0: POST message:send, POST message:stream (SSE), GET tasks, GET tasks/{id}, POST tasks/{id}:cancel, GET|POST tasks/{id}:subscribe (SSE), POST|GET tasks/{id}/pushNotificationConfigs, GET|DELETE tasks/{id}/pushNotificationConfigs/{configId}, GET extendedAgentCard. v0.3 (no header): same paths with v0.3 ProtoJSON plus GET card.",
        "parameters": [
          {
            "name": "A2A-Version",
            "in": "header",
            "required": false,
            "schema": {
              "type": "string",
              "enum": [
                "1.0",
                "0.3"
              ]
            },
            "description": "Protocol version; empty means 0.3"
          },
          {
            "name": "agent",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "enum": [
                "echo",
                "weather",
                "travel-planner",
                "approval",
                "flaky",
                "secure",
                "reject"
              ]
            }
          }
        ],
        "responses": {
          "200": {
            "description": "A2A response",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object"
              }
            }
          }
        }
      }
    },
    "/a2a/{agent}/v1/message:stream": {
      "post": {
        "tags": [
          "A2A Agents"
        ],
        "summary": "REST SendStreamingMessage (SSE)",
        "operationId": "a2aRestSendStreamingMessage",
        "description": "HTTP+JSON binding. v1.0: POST message:send, POST message:stream (SSE), GET tasks, GET tasks/{id}, POST tasks/{id}:cancel, GET|POST tasks/{id}:subscribe (SSE), POST|GET tasks/{id}/pushNotificationConfigs, GET|DELETE tasks/{id}/pushNotificationConfigs/{configId}, GET extendedAgentCard. v0.3 (no header): same paths with v0.3 ProtoJSON plus GET card.",
        "parameters": [
          {
            "name": "A2A-Version",
            "in": "header",
            "required": false,
            "schema": {
              "type": "string",
              "enum": [
                "1.0",
                "0.3"
              ]
            },
            "description": "Protocol version; empty means 0.3"
          },
          {
            "name": "agent",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "enum": [
                "echo",
                "weather",
                "travel-planner",
                "approval",
                "flaky",
                "secure",
                "reject"
              ]
            }
          }
        ],
        "responses": {
          "200": {
            "description": "A2A response",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object"
              }
            }
          }
        }
      }
    },
    "/a2a/{agent}/v1/tasks": {
      "get": {
        "tags": [
          "A2A Agents"
        ],
        "summary": "REST ListTasks (contextId, status, pageSize, pageToken, historyLength, statusTimestampAfter, includeArtifacts)",
        "operationId": "a2aRestListTasks",
        "description": "HTTP+JSON binding. v1.0: POST message:send, POST message:stream (SSE), GET tasks, GET tasks/{id}, POST tasks/{id}:cancel, GET|POST tasks/{id}:subscribe (SSE), POST|GET tasks/{id}/pushNotificationConfigs, GET|DELETE tasks/{id}/pushNotificationConfigs/{configId}, GET extendedAgentCard. v0.3 (no header): same paths with v0.3 ProtoJSON plus GET card.",
        "parameters": [
          {
            "name": "A2A-Version",
            "in": "header",
            "required": false,
            "schema": {
              "type": "string",
              "enum": [
                "1.0",
                "0.3"
              ]
            },
            "description": "Protocol version; empty means 0.3"
          },
          {
            "name": "agent",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "enum": [
                "echo",
                "weather",
                "travel-planner",
                "approval",
                "flaky",
                "secure",
                "reject"
              ]
            }
          }
        ],
        "responses": {
          "200": {
            "description": "A2A response",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          }
        }
      }
    },
    "/a2a/{agent}/v1/extendedAgentCard": {
      "get": {
        "tags": [
          "A2A Agents"
        ],
        "summary": "REST GetExtendedAgentCard (bearer token)",
        "operationId": "a2aRestExtendedAgentCard",
        "description": "HTTP+JSON binding. v1.0: POST message:send, POST message:stream (SSE), GET tasks, GET tasks/{id}, POST tasks/{id}:cancel, GET|POST tasks/{id}:subscribe (SSE), POST|GET tasks/{id}/pushNotificationConfigs, GET|DELETE tasks/{id}/pushNotificationConfigs/{configId}, GET extendedAgentCard. v0.3 (no header): same paths with v0.3 ProtoJSON plus GET card.",
        "parameters": [
          {
            "name": "A2A-Version",
            "in": "header",
            "required": false,
            "schema": {
              "type": "string",
              "enum": [
                "1.0",
                "0.3"
              ]
            },
            "description": "Protocol version; empty means 0.3"
          },
          {
            "name": "agent",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "enum": [
                "echo",
                "weather",
                "travel-planner",
                "approval",
                "flaky",
                "secure",
                "reject"
              ]
            }
          }
        ],
        "responses": {
          "200": {
            "description": "A2A response",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          }
        }
      }
    },
    "/a2a/webhook-sink/{id}": {
      "get": {
        "tags": [
          "A2A Agents"
        ],
        "summary": "List push notifications received by a sink",
        "operationId": "a2aSinkList",
        "description": "Bounded: 50 notifications per sink, idle sinks expire after an hour",
        "parameters": [
          {
            "name": "A2A-Version",
            "in": "header",
            "required": false,
            "schema": {
              "type": "string",
              "enum": [
                "1.0",
                "0.3"
              ]
            },
            "description": "Protocol version; empty means 0.3"
          }
        ],
        "responses": {
          "200": {
            "description": "A2A response",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          }
        }
      },
      "post": {
        "tags": [
          "A2A Agents"
        ],
        "summary": "Record a push notification",
        "operationId": "a2aSinkRecord",
        "description": "Any JSON body; selected headers are stored",
        "parameters": [
          {
            "name": "A2A-Version",
            "in": "header",
            "required": false,
            "schema": {
              "type": "string",
              "enum": [
                "1.0",
                "0.3"
              ]
            },
            "description": "Protocol version; empty means 0.3"
          }
        ],
        "responses": {
          "200": {
            "description": "A2A response",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object"
              }
            }
          }
        }
      },
      "delete": {
        "tags": [
          "A2A Agents"
        ],
        "summary": "Clear a sink",
        "operationId": "a2aSinkClear",
        "description": "Removes all stored notifications",
        "parameters": [
          {
            "name": "A2A-Version",
            "in": "header",
            "required": false,
            "schema": {
              "type": "string",
              "enum": [
                "1.0",
                "0.3"
              ]
            },
            "description": "Protocol version; empty means 0.3"
          }
        ],
        "responses": {
          "200": {
            "description": "A2A response",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          }
        }
      }
    }
  },
  "components": {
    "schemas": {
      "ErrorResponse": {
        "type": "object",
        "properties": {
          "error": {
            "type": "string",
            "example": "bad_request"
          },
          "details": {
            "type": "string",
            "example": "Detailed error description",
            "nullable": true
          }
        },
        "required": [
          "error"
        ]
      },
      "AuthResponse": {
        "type": "object",
        "properties": {
          "authenticated": {
            "type": "boolean"
          },
          "auth_type": {
            "type": "string",
            "enum": [
              "basic-auth",
              "api-key",
              "hmac",
              "jwt",
              "mtls"
            ]
          },
          "username": {
            "type": "string",
            "nullable": true
          },
          "header": {
            "type": "string",
            "nullable": true
          },
          "claims": {
            "type": "object",
            "nullable": true
          },
          "jwt_header": {
            "type": "object",
            "nullable": true
          },
          "client_dn": {
            "type": "string",
            "nullable": true
          },
          "client_ca": {
            "type": "string",
            "nullable": true
          }
        },
        "required": [
          "authenticated",
          "auth_type"
        ]
      },
      "AuthFailure": {
        "type": "object",
        "properties": {
          "authenticated": {
            "type": "boolean",
            "example": false
          },
          "error": {
            "type": "string",
            "example": "unauthorized"
          }
        },
        "required": [
          "authenticated",
          "error"
        ]
      },
      "EchoResponse": {
        "type": "object",
        "properties": {
          "method": {
            "type": "string",
            "example": "GET"
          },
          "url": {
            "type": "string",
            "example": "https://api.example.com/echo?a=1",
            "description": "As the client used it (trusted X-Forwarded-Proto/Host/Port and Forwarded applied)"
          },
          "path": {
            "type": "string",
            "example": "/echo"
          },
          "path_info": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "query_string": {
            "type": "string"
          },
          "query_params": {
            "type": "object",
            "additionalProperties": {
              "type": "string"
            }
          },
          "headers": {
            "type": "object",
            "additionalProperties": {
              "type": "array",
              "items": {
                "type": "string"
              }
            }
          },
          "host": {
            "type": "string"
          },
          "port": {
            "type": "integer"
          },
          "scheme": {
            "type": "string"
          },
          "remote_ip": {
            "type": "string"
          },
          "body": {
            "$ref": "#/components/schemas/EchoBody"
          },
          "timestamp_unix_ms": {
            "type": "integer",
            "format": "int64"
          }
        }
      },
      "EchoBody": {
        "type": "object",
        "properties": {
          "present": {
            "type": "boolean"
          },
          "included": {
            "type": "boolean"
          },
          "body": {
            "type": "string",
            "nullable": true
          },
          "bytes": {
            "type": "integer"
          },
          "truncated": {
            "type": "boolean"
          },
          "utf8": {
            "type": "boolean"
          },
          "reason": {
            "type": "string",
            "nullable": true
          }
        }
      },
      "IdentityResponse": {
        "type": "object",
        "properties": {
          "instance_id": {
            "type": "string",
            "format": "uuid"
          },
          "hostname": {
            "type": "string"
          },
          "version": {
            "type": "string"
          },
          "uptime_seconds": {
            "type": "integer"
          },
          "request_count": {
            "type": "integer"
          },
          "port": {
            "type": "object",
            "properties": {
              "http": {
                "type": "integer"
              },
              "https": {
                "type": "integer"
              },
              "grpc": {
                "type": "integer"
              },
              "listener": {
                "type": "object",
                "properties": {
                  "scheme": {
                    "type": "string"
                  },
                  "port": {
                    "type": "integer"
                  }
                }
              }
            }
          },
          "config": {
            "type": "object",
            "properties": {
              "host": {
                "type": "string"
              },
              "public_mode": {
                "type": "boolean"
              },
              "trust_forward": {
                "type": "boolean"
              },
              "body_limit": {
                "type": "integer"
              },
              "request_timeout_secs": {
                "type": "integer"
              },
              "max_delay_ms": {
                "type": "integer"
              },
              "inspector_capacity": {
                "type": "integer"
              },
              "cors_allow_origins": {
                "type": "array",
                "items": {
                  "type": "string"
                }
              },
              "admin_token_configured": {
                "type": "boolean"
              }
            }
          },
          "environment": {
            "type": "object",
            "properties": {
              "rust_version": {
                "type": "string",
                "example": "rustc 1.86.0 (05f9846f8 2025-03-31)"
              },
              "msrv": {
                "type": "string"
              },
              "profile": {
                "type": "string"
              },
              "os": {
                "type": "string"
              },
              "arch": {
                "type": "string"
              }
            }
          },
          "request": {
            "type": "object",
            "properties": {
              "method": {
                "type": "string"
              },
              "peer_ip": {
                "type": "string"
              },
              "remote_ip": {
                "type": "string"
              },
              "forwarded_for": {
                "type": "string",
                "nullable": true
              },
              "forwarded": {
                "type": "string",
                "nullable": true
              },
              "host": {
                "type": "string"
              },
              "scheme": {
                "type": "string"
              },
              "url_base": {
                "type": "string"
              },
              "via": {
                "type": "string",
                "nullable": true
              }
            }
          },
          "timestamp": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "FlakySuccess": {
        "type": "object",
        "properties": {
          "status": {
            "type": "string",
            "example": "ok"
          },
          "fail_rate": {
            "type": "integer"
          },
          "message": {
            "type": "string",
            "example": "Request succeeded"
          },
          "request_number": {
            "type": "integer"
          }
        }
      },
      "FlakyFailure": {
        "type": "object",
        "properties": {
          "error": {
            "type": "string",
            "example": "service_unavailable"
          },
          "fail_rate": {
            "type": "integer"
          },
          "message": {
            "type": "string",
            "example": "Simulated failure (50% fail rate)"
          }
        }
      },
      "CapturedRequest": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string"
          },
          "request_id": {
            "type": "string",
            "nullable": true
          },
          "timestamp": {
            "type": "string",
            "format": "date-time"
          },
          "method": {
            "type": "string"
          },
          "uri": {
            "type": "string"
          },
          "path": {
            "type": "string"
          },
          "query": {
            "type": "string",
            "nullable": true
          },
          "version": {
            "type": "string"
          },
          "headers": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "name": {
                  "type": "string"
                },
                "value": {
                  "type": "string"
                }
              }
            }
          },
          "client_ip": {
            "type": "string",
            "nullable": true
          },
          "session": {
            "type": "string",
            "nullable": true
          },
          "key_id": {
            "type": "string",
            "description": "API key id (shared mode, RUSTYBIN_REQUIRE_KEY); absent otherwise"
          },
          "body": {
            "type": "string",
            "nullable": true
          },
          "body_base64": {
            "type": "string",
            "nullable": true
          },
          "body_size": {
            "type": "integer"
          },
          "body_truncated": {
            "type": "boolean"
          },
          "status": {
            "type": "integer"
          },
          "latency_ms": {
            "type": "number"
          }
        }
      },
      "HarnessScenario": {
        "type": "object",
        "description": "A harness scenario: targets, layers with sources and patterns, scale, timeout and thresholds. The full JSON Schema with descriptions and this node's bounds is served at GET /_rustybin/harness/schema.",
        "required": [
          "name"
        ],
        "properties": {
          "name": {
            "type": "string"
          },
          "description": {
            "type": "string"
          },
          "target": {
            "type": "string",
            "description": "Shorthand for one target URL"
          },
          "targets": {
            "type": "array",
            "items": {
              "type": "object"
            }
          },
          "scale": {
            "type": "object"
          },
          "layers": {
            "type": "array",
            "items": {
              "type": "object"
            }
          },
          "source": {
            "type": "object",
            "description": "Shorthand: the source of a single layer"
          },
          "pattern": {
            "type": "object",
            "description": "Shorthand: the pattern of a single layer"
          },
          "model": {
            "type": "string",
            "enum": [
              "open",
              "closed"
            ]
          },
          "think_time": {
            "type": "string"
          },
          "timeout": {
            "type": "string"
          },
          "thresholds": {
            "type": "object"
          }
        }
      },
      "McpJsonRpcMessage": {
        "type": "object",
        "description": "A JSON-RPC 2.0 request, notification or response",
        "required": [
          "jsonrpc"
        ],
        "properties": {
          "jsonrpc": {
            "type": "string",
            "enum": [
              "2.0"
            ]
          },
          "id": {
            "oneOf": [
              {
                "type": "string"
              },
              {
                "type": "integer"
              }
            ]
          },
          "method": {
            "type": "string"
          },
          "params": {
            "type": "object"
          },
          "result": {
            "type": "object"
          },
          "error": {
            "type": "object"
          }
        }
      },
      "RegistryProblem": {
        "type": "object",
        "properties": {
          "title": {
            "type": "string"
          },
          "status": {
            "type": "integer"
          },
          "detail": {
            "type": "string"
          },
          "errors": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "message": {
                  "type": "string"
                },
                "location": {
                  "type": "string"
                },
                "value": {}
              }
            }
          }
        }
      },
      "RegistryServerJson": {
        "type": "object",
        "description": "A server.json document (https://static.modelcontextprotocol.io/schemas/2025-12-11/server.schema.json)",
        "required": [
          "name",
          "description",
          "version"
        ],
        "properties": {
          "$schema": {
            "type": "string",
            "format": "uri"
          },
          "name": {
            "type": "string",
            "pattern": "^[a-zA-Z0-9.-]+/[a-zA-Z0-9._-]+$"
          },
          "title": {
            "type": "string"
          },
          "description": {
            "type": "string",
            "maxLength": 100
          },
          "version": {
            "type": "string"
          },
          "websiteUrl": {
            "type": "string",
            "format": "uri"
          },
          "repository": {
            "type": "object"
          },
          "remotes": {
            "type": "array",
            "items": {
              "type": "object"
            }
          },
          "packages": {
            "type": "array",
            "items": {
              "type": "object"
            }
          },
          "_meta": {
            "type": "object"
          }
        }
      },
      "RegistryServerResponse": {
        "type": "object",
        "required": [
          "server",
          "_meta"
        ],
        "properties": {
          "server": {
            "$ref": "#/components/schemas/RegistryServerJson"
          },
          "_meta": {
            "type": "object",
            "properties": {
              "io.modelcontextprotocol.registry/official": {
                "type": "object",
                "properties": {
                  "status": {
                    "type": "string",
                    "enum": [
                      "active",
                      "deprecated",
                      "deleted"
                    ]
                  },
                  "statusMessage": {
                    "type": "string"
                  },
                  "statusChangedAt": {
                    "type": "string",
                    "format": "date-time"
                  },
                  "publishedAt": {
                    "type": "string",
                    "format": "date-time"
                  },
                  "updatedAt": {
                    "type": "string",
                    "format": "date-time"
                  },
                  "isLatest": {
                    "type": "boolean"
                  }
                }
              }
            }
          }
        }
      },
      "RegistryServerList": {
        "type": "object",
        "required": [
          "servers",
          "metadata"
        ],
        "properties": {
          "servers": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/RegistryServerResponse"
            }
          },
          "metadata": {
            "type": "object",
            "required": [
              "count"
            ],
            "properties": {
              "count": {
                "type": "integer"
              },
              "nextCursor": {
                "type": "string"
              }
            }
          }
        }
      },
      "RegistryValidation": {
        "type": "object",
        "required": [
          "valid",
          "issues"
        ],
        "properties": {
          "valid": {
            "type": "boolean"
          },
          "issues": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "type": {
                  "type": "string"
                },
                "path": {
                  "type": "string"
                },
                "message": {
                  "type": "string"
                },
                "severity": {
                  "type": "string",
                  "enum": [
                    "error",
                    "warning"
                  ]
                },
                "reference": {
                  "type": "string"
                }
              }
            }
          }
        }
      },
      "ChatCompletionRequest": {
        "type": "object",
        "required": [
          "messages"
        ],
        "properties": {
          "model": {
            "type": "string",
            "example": "rustybin-gpt"
          },
          "messages": {
            "type": "array",
            "items": {
              "type": "object",
              "required": [
                "role"
              ],
              "properties": {
                "role": {
                  "type": "string",
                  "enum": [
                    "system",
                    "developer",
                    "user",
                    "assistant",
                    "tool",
                    "function"
                  ]
                },
                "content": {
                  "nullable": true,
                  "oneOf": [
                    {
                      "type": "string"
                    },
                    {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "type": {
                            "type": "string",
                            "enum": [
                              "text",
                              "image_url",
                              "input_audio",
                              "file",
                              "refusal"
                            ]
                          },
                          "text": {
                            "type": "string"
                          },
                          "image_url": {
                            "type": "object",
                            "properties": {
                              "url": {
                                "type": "string"
                              }
                            }
                          }
                        }
                      }
                    }
                  ]
                },
                "tool_calls": {
                  "type": "array",
                  "items": {
                    "type": "object"
                  }
                },
                "tool_call_id": {
                  "type": "string"
                }
              }
            }
          },
          "stream": {
            "type": "boolean",
            "default": false
          },
          "stream_options": {
            "type": "object",
            "properties": {
              "include_usage": {
                "type": "boolean"
              }
            }
          },
          "n": {
            "type": "integer",
            "minimum": 1,
            "maximum": 8
          },
          "max_tokens": {
            "type": "integer"
          },
          "max_completion_tokens": {
            "type": "integer"
          },
          "stop": {
            "oneOf": [
              {
                "type": "string"
              },
              {
                "type": "array",
                "items": {
                  "type": "string"
                }
              }
            ]
          },
          "temperature": {
            "type": "number",
            "minimum": 0,
            "maximum": 2
          },
          "tools": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "type": {
                  "type": "string",
                  "enum": [
                    "function"
                  ]
                },
                "function": {
                  "type": "object",
                  "properties": {
                    "name": {
                      "type": "string"
                    },
                    "description": {
                      "type": "string"
                    },
                    "parameters": {
                      "type": "object"
                    }
                  }
                }
              }
            }
          },
          "tool_choice": {
            "oneOf": [
              {
                "type": "string",
                "enum": [
                  "none",
                  "auto",
                  "required"
                ]
              },
              {
                "type": "object"
              }
            ]
          },
          "response_format": {
            "type": "object",
            "properties": {
              "type": {
                "type": "string",
                "enum": [
                  "text",
                  "json_object",
                  "json_schema"
                ]
              },
              "json_schema": {
                "type": "object"
              }
            }
          }
        }
      },
      "ChatCompletionResponse": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "example": "chatcmpl-abc123"
          },
          "object": {
            "type": "string",
            "example": "chat.completion"
          },
          "created": {
            "type": "integer"
          },
          "model": {
            "type": "string"
          },
          "choices": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "index": {
                  "type": "integer"
                },
                "message": {
                  "type": "object",
                  "properties": {
                    "role": {
                      "type": "string"
                    },
                    "content": {
                      "type": "string",
                      "nullable": true
                    },
                    "tool_calls": {
                      "type": "array",
                      "items": {
                        "type": "object"
                      }
                    }
                  }
                },
                "logprobs": {
                  "nullable": true
                },
                "finish_reason": {
                  "type": "string",
                  "enum": [
                    "stop",
                    "length",
                    "tool_calls",
                    "content_filter"
                  ]
                }
              }
            }
          },
          "usage": {
            "type": "object",
            "properties": {
              "prompt_tokens": {
                "type": "integer"
              },
              "completion_tokens": {
                "type": "integer"
              },
              "total_tokens": {
                "type": "integer"
              }
            }
          }
        }
      },
      "AnthropicMessagesRequest": {
        "type": "object",
        "required": [
          "model",
          "max_tokens",
          "messages"
        ],
        "properties": {
          "model": {
            "type": "string",
            "example": "claude-sonnet-4-5"
          },
          "max_tokens": {
            "type": "integer",
            "example": 256
          },
          "system": {
            "oneOf": [
              {
                "type": "string"
              },
              {
                "type": "array",
                "items": {
                  "type": "object",
                  "properties": {
                    "type": {
                      "type": "string"
                    },
                    "text": {
                      "type": "string"
                    },
                    "cache_control": {
                      "type": "object"
                    }
                  }
                }
              }
            ]
          },
          "messages": {
            "type": "array",
            "items": {
              "type": "object",
              "required": [
                "role",
                "content"
              ],
              "properties": {
                "role": {
                  "type": "string",
                  "enum": [
                    "user",
                    "assistant"
                  ]
                },
                "content": {
                  "oneOf": [
                    {
                      "type": "string"
                    },
                    {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "type": {
                            "type": "string",
                            "enum": [
                              "text",
                              "image",
                              "document",
                              "tool_use",
                              "tool_result"
                            ]
                          }
                        }
                      }
                    }
                  ]
                }
              }
            }
          },
          "tools": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "name": {
                  "type": "string"
                },
                "description": {
                  "type": "string"
                },
                "input_schema": {
                  "type": "object"
                }
              }
            }
          },
          "tool_choice": {
            "type": "object",
            "properties": {
              "type": {
                "type": "string",
                "enum": [
                  "auto",
                  "any",
                  "tool",
                  "none"
                ]
              },
              "name": {
                "type": "string"
              }
            }
          },
          "stop_sequences": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "stream": {
            "type": "boolean",
            "default": false
          }
        }
      },
      "AnthropicMessage": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string"
          },
          "type": {
            "type": "string",
            "example": "message"
          },
          "role": {
            "type": "string"
          },
          "model": {
            "type": "string"
          },
          "content": {
            "type": "array",
            "items": {
              "type": "object"
            }
          },
          "stop_reason": {
            "type": "string",
            "enum": [
              "end_turn",
              "max_tokens",
              "stop_sequence",
              "tool_use",
              "refusal"
            ]
          },
          "stop_sequence": {
            "type": "string",
            "nullable": true
          },
          "usage": {
            "type": "object",
            "properties": {
              "input_tokens": {
                "type": "integer"
              },
              "output_tokens": {
                "type": "integer"
              },
              "cache_creation_input_tokens": {
                "type": "integer"
              },
              "cache_read_input_tokens": {
                "type": "integer"
              }
            }
          }
        }
      },
      "AiRequestRecord": {
        "type": "object",
        "properties": {
          "request_id": {
            "type": "string"
          },
          "provider": {
            "type": "string"
          },
          "endpoint": {
            "type": "string"
          },
          "model": {
            "type": "string"
          },
          "mode": {
            "type": "string"
          },
          "stream": {
            "type": "boolean"
          },
          "credential": {
            "type": "string",
            "nullable": true
          },
          "headers": {
            "type": "object",
            "additionalProperties": {
              "type": "string"
            }
          },
          "body": {},
          "normalized_prompt": {
            "type": "string"
          },
          "usage": {
            "type": "object",
            "properties": {
              "prompt_tokens": {
                "type": "integer"
              },
              "completion_tokens": {
                "type": "integer"
              },
              "total_tokens": {
                "type": "integer"
              }
            }
          },
          "finish_reason": {
            "type": "string"
          },
          "reply_preview": {
            "type": "string"
          },
          "captured": {
            "type": "object",
            "nullable": true
          }
        }
      }
    },
    "securitySchemes": {
      "basicAuth": {
        "type": "http",
        "scheme": "basic",
        "description": "HTTP Basic authentication. Default credentials: basic:password"
      },
      "bearerAuth": {
        "type": "http",
        "scheme": "bearer",
        "bearerFormat": "JWT",
        "description": "JWT Bearer token authentication"
      },
      "apiKeyAuth": {
        "type": "apiKey",
        "in": "header",
        "name": "apikey",
        "description": "API key in header. Default key: my-key"
      },
      "mcpApiKey": {
        "type": "apiKey",
        "in": "header",
        "name": "X-API-Key"
      }
    },
    "RustybinSettings": {
      "type": "object",
      "properties": {
        "persisted": {
          "type": "boolean",
          "description": "Changes are written to RUSTYBIN_STATE_DIR"
        },
        "locked": {
          "type": "boolean",
          "description": "RUSTYBIN_SETTINGS_LOCK is on"
        },
        "secrets_key": {
          "type": "string",
          "enum": [
            "env",
            "file",
            "process"
          ]
        },
        "updated_at": {
          "type": [
            "string",
            "null"
          ],
          "format": "date-time"
        },
        "unreadable_secrets": {
          "type": "array",
          "items": {
            "type": "string"
          }
        },
        "groups": {
          "type": "array",
          "items": {
            "type": "object",
            "properties": {
              "id": {
                "type": "string"
              },
              "title": {
                "type": "string"
              },
              "description": {
                "type": "string"
              }
            }
          }
        },
        "settings": {
          "type": "array",
          "items": {
            "type": "object",
            "properties": {
              "key": {
                "type": "string"
              },
              "group": {
                "type": "string"
              },
              "title": {
                "type": "string"
              },
              "description": {
                "type": "string"
              },
              "schema": {
                "type": "object",
                "description": "JSON Schema of the value"
              },
              "default": {},
              "secret": {
                "type": "boolean"
              },
              "env": {
                "type": [
                  "string",
                  "null"
                ]
              },
              "lockable": {
                "type": "boolean"
              },
              "locked": {
                "type": "boolean"
              },
              "stored": {
                "type": "boolean"
              },
              "value": {
                "description": "The effective value, or `{set, hint, source, unreadable}` for a secret"
              },
              "source": {
                "type": [
                  "string",
                  "null"
                ],
                "enum": [
                  "stored",
                  "env",
                  "default",
                  null
                ]
              }
            }
          }
        },
        "changed": {
          "type": "array",
          "items": {
            "type": "string"
          },
          "description": "After a write: the keys that changed"
        }
      }
    }
  }
}