{
  "openapi": "3.1.0",
  "info": {
    "title": "Strix API",
    "version": "1.0.0",
    "description": "Public REST API for the Strix autonomous penetration testing platform. Manage scans, vulnerabilities, assets, schedules, API tokens, and webhooks."
  },
  "servers": [
    {
      "url": "/api/v1",
      "description": "Strix v1 API"
    }
  ],
  "security": [
    {
      "BearerAuth": []
    }
  ],
  "paths": {
    "/scans": {
      "get": {
        "operationId": "listScans",
        "summary": "List scans",
        "description": "Returns a paginated list of scans for the authenticated organization. Each scan carries finding counts. A pentest's counts omit dependency CVE findings. A supply-chain scan's findings are all dependency CVEs, so its counts are nonzero only when the token also holds the `dependencies:read` scope.",
        "tags": ["Scans"],
        "security": [
          {
            "BearerAuth": ["scans:read"]
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/Page"
          },
          {
            "$ref": "#/components/parameters/Limit"
          },
          {
            "description": "Return only scans in this status.",
            "name": "status",
            "in": "query",
            "schema": {
              "$ref": "#/components/schemas/ScanStatus"
            }
          },
          {
            "description": "Return only scans of this type. `whitebox` scans include source code, `blackbox` scans test targets externally.",
            "name": "scan_type",
            "in": "query",
            "schema": {
              "type": "string",
              "enum": ["whitebox", "blackbox"]
            }
          },
          {
            "name": "date_from",
            "in": "query",
            "description": "Filter scans created on or after this date (ISO 8601).",
            "schema": {
              "type": "string",
              "format": "date-time"
            }
          },
          {
            "name": "date_to",
            "in": "query",
            "description": "Filter scans created on or before this date (inclusive, end-of-day).",
            "schema": {
              "type": "string",
              "format": "date-time"
            }
          },
          {
            "description": "Return only scans that target this domain UUID.",
            "name": "domain_id",
            "in": "query",
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          },
          {
            "name": "repository_id",
            "in": "query",
            "description": "Return only the scans that include this repository.",
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          },
          {
            "name": "search",
            "in": "query",
            "description": "Case-insensitive substring match on the scan title.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "include_retests",
            "in": "query",
            "description": "Include per-finding retest scans in the results. Excluded by default, matching the dashboard pentest list.",
            "schema": {
              "type": "boolean",
              "default": false
            }
          },
          {
            "$ref": "#/components/parameters/SortBy_CreatedAt"
          },
          {
            "$ref": "#/components/parameters/SortOrder"
          }
        ],
        "responses": {
          "200": {
            "description": "Paginated list of scans.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/PaginatedResponse_Scan"
                    },
                    {
                      "type": "object",
                      "properties": {
                        "scansThisMonth": {
                          "type": "integer"
                        }
                      }
                    }
                  ]
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        }
      },
      "post": {
        "operationId": "createScan",
        "summary": "Create a scan",
        "description": "Launch a new penetration test scan against the specified targets. For retry-safe at-most-once creation, send an Idempotency-Key and reuse the exact same key and request after a lost or ambiguous response. The key is optional for backward compatibility, retained for 24 hours, and cannot be reused with a different actor, operation, or payload. A terminal response is replayed only after the caller still passes current target/resource authorization; revoked access returns a fresh 403/404 without exposing the receipt. Use a new key only for a deliberate new attempt.",
        "tags": ["Scans"],
        "security": [
          {
            "BearerAuth": ["scans:write"]
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreateScanRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Scan created successfully.",
            "headers": {
              "Idempotency-Key": {
                "$ref": "#/components/headers/IdempotencyKeyResponse"
              },
              "Idempotency-Replayed": {
                "$ref": "#/components/headers/IdempotencyReplayed"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CreateScanResponse"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/IdempotencyBadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "402": {
            "$ref": "#/components/responses/PaymentRequired"
          },
          "403": {
            "$ref": "#/components/responses/TierLimitError"
          },
          "409": {
            "$ref": "#/components/responses/IdempotencyConflictOrInProgress"
          },
          "503": {
            "$ref": "#/components/responses/IdempotencyOutcomeUnknown"
          },
          "500": {
            "$ref": "#/components/responses/IdempotencyInternalOrAbandoned"
          }
        }
      }
    },
    "/scans/{scanId}": {
      "get": {
        "operationId": "getScan",
        "summary": "Get scan details",
        "description": "Returns full scan details including associated vulnerabilities. A pentest's list omits dependency CVE findings. A supply-chain scan's findings are all dependency CVEs. The response embeds them only when the token also holds the `dependencies:read` scope. Without that scope, the list is empty.",
        "tags": ["Scans"],
        "security": [
          {
            "BearerAuth": ["scans:read"]
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/ScanId"
          }
        ],
        "responses": {
          "200": {
            "description": "Scan details with vulnerabilities.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ScanWithVulnerabilities"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          },
          "503": {
            "description": "The SBOM was replaced while it was being read. Retry the request.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          }
        }
      },
      "patch": {
        "operationId": "renameScan",
        "summary": "Rename a scan",
        "description": "Sets a new scan title. The server trims the title and accepts 1 to 120 characters.",
        "tags": [
          "Scans"
        ],
        "security": [
          {
            "BearerAuth": [
              "scans:write"
            ]
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/ScanId"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/RenameScanRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Scan renamed.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "scan_id": {
                      "type": "string",
                      "format": "uuid"
                    },
                    "title": {
                      "type": "string"
                    }
                  },
                  "required": [
                    "scan_id",
                    "title"
                  ]
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        }
      },
      "delete": {
        "operationId": "deleteScan",
        "summary": "Delete a scan",
        "description": "Permanently deletes a scan and its findings.",
        "tags": ["Scans"],
        "security": [
          {
            "BearerAuth": ["scans:write"]
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/ScanId"
          }
        ],
        "responses": {
          "200": {
            "description": "Scan deleted.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SuccessResponse"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        }
      }
    },
    "/scans/{scanId}/cancel": {
      "post": {
        "operationId": "cancelScan",
        "summary": "Cancel a scan",
        "description": "Cancel a pending or running scan. Credits may be refunded if cancelled within 5 minutes.",
        "tags": ["Scans"],
        "security": [
          {
            "BearerAuth": ["scans:write"]
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/ScanId"
          }
        ],
        "responses": {
          "200": {
            "description": "Scan cancelled.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "message": {
                      "type": "string"
                    }
                  },
                  "required": ["message"]
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        }
      }
    },
    "/scans/{scanId}/message": {
      "post": {
        "operationId": "sendScanMessage",
        "summary": "Send a scan message",
        "description": "Sends a live prompt to a running scan. `message` is required unless `cancel_current` is true. You must provide at least one of these fields.",
        "tags": ["Scans"],
        "security": [
          {
            "BearerAuth": ["scans:message"]
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/ScanId"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "message": {
                    "type": "string",
                    "description": "Message to send to the running scan."
                  },
                  "cancel_current": {
                    "type": "boolean",
                    "description": "Cancel the current execution before or while delivering the prompt."
                  },
                  "agent_id": {
                    "type": "string",
                    "description": "Optional target agent id. Defaults to the scan root agent."
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Message sent successfully.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    }
                  },
                  "required": ["success"]
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "$ref": "#/components/responses/Conflict"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          },
          "502": {
            "$ref": "#/components/responses/BadGateway"
          },
          "503": {
            "$ref": "#/components/responses/ServiceUnavailable"
          }
        }
      }
    },
    "/scans/{scanId}/rerun": {
      "post": {
        "operationId": "rerunScan",
        "summary": "Rerun a scan",
        "description": "Create a new scan with the same configuration as the specified scan. For retry-safe at-most-once creation, send an Idempotency-Key and reuse the exact same key and request after a lost or ambiguous response. The key is optional for backward compatibility, retained for 24 hours, and cannot be reused with a different actor, operation, or source scan. A terminal response is replayed only after the caller still passes current source-scan authorization; revoked access returns a fresh 403/404 without exposing the receipt. Use a new key only for a deliberate new rerun.",
        "tags": ["Scans"],
        "security": [
          {
            "BearerAuth": ["scans:write"]
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/ScanId"
          },
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "responses": {
          "200": {
            "description": "Rerun scan created.",
            "headers": {
              "Idempotency-Key": {
                "$ref": "#/components/headers/IdempotencyKeyResponse"
              },
              "Idempotency-Replayed": {
                "$ref": "#/components/headers/IdempotencyReplayed"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CreateScanResponse"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/IdempotencyBadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "402": {
            "$ref": "#/components/responses/PaymentRequired"
          },
          "403": {
            "$ref": "#/components/responses/TierLimitError"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "$ref": "#/components/responses/IdempotencyConflictOrInProgress"
          },
          "503": {
            "$ref": "#/components/responses/IdempotencyOutcomeUnknown"
          },
          "500": {
            "$ref": "#/components/responses/IdempotencyInternalOrAbandoned"
          }
        }
      }
    },
    "/scans/{scanId}/report": {
      "get": {
        "operationId": "getScanReport",
        "summary": "Download scan report",
        "description": "Generate and download a report for a completed scan. Report downloads require an Enterprise plan.",
        "tags": ["Scans"],
        "security": [
          {
            "BearerAuth": ["scans:read"]
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/ScanId"
          },
          {
            "name": "format",
            "in": "query",
            "description": "Report format. Formats other than \"technical\" require an Enterprise plan.",
            "schema": {
              "type": "string",
              "enum": [
                "technical",
                "retest",
                "attestation",
                "executive_summary"
              ],
              "default": "technical"
            }
          },
          {
            "name": "type",
            "in": "query",
            "description": "File type for the rendered report. DOCX requires an Enterprise plan.",
            "schema": {
              "type": "string",
              "enum": ["pdf", "docx"],
              "default": "pdf"
            }
          },
          {
            "name": "providerName",
            "in": "query",
            "description": "White-label provider name shown on the report cover (Enterprise branding). Trimmed to 80 characters.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "memberName0",
            "in": "query",
            "description": "Name of the first \"prepared by\" team member for white-label branding. Trimmed to 120 characters.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "memberEmail0",
            "in": "query",
            "description": "Email of the first \"prepared by\" team member for white-label branding. Trimmed to 120 characters.",
            "schema": {
              "type": "string",
              "format": "email"
            }
          },
          {
            "name": "memberName1",
            "in": "query",
            "description": "Name of the second \"prepared by\" team member for white-label branding. Trimmed to 120 characters.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "memberEmail1",
            "in": "query",
            "description": "Email of the second \"prepared by\" team member for white-label branding. Trimmed to 120 characters.",
            "schema": {
              "type": "string",
              "format": "email"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Report file. Content type is `application/pdf` by default, or the DOCX media type when `type=docx`.",
            "content": {
              "application/pdf": {
                "schema": {
                  "type": "string",
                  "format": "binary"
                }
              },
              "application/vnd.openxmlformats-officedocument.wordprocessingml.document": {
                "schema": {
                  "type": "string",
                  "format": "binary"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        }
      }
    },
    "/scans/{scanId}/sarif": {
      "get": {
        "operationId": "getScanSarif",
        "summary": "Download scan SARIF",
        "description": "Generate a SARIF 2.1.0 export for active vulnerabilities on a scan.",
        "tags": ["Scans"],
        "security": [
          {
            "BearerAuth": ["scans:read"]
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/ScanId"
          },
          {
            "name": "repository",
            "in": "query",
            "description": "Repository full name (`owner/repo`) to scope SARIF results for multi-repository scans.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "SARIF 2.1.0 log.",
            "content": {
              "application/sarif+json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        }
      },
      "post": {
        "operationId": "uploadScanSarif",
        "summary": "Upload scan SARIF to GitHub",
        "description": "Generate SARIF for active scan vulnerabilities and upload it to GitHub code scanning. Requires an Enterprise plan.",
        "tags": ["Scans"],
        "security": [
          {
            "BearerAuth": ["scans:write"]
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/ScanId"
          }
        ],
        "requestBody": {
          "required": false,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "repository": {
                    "type": "string",
                    "description": "Repository full name (`owner/repo`) to upload SARIF for."
                  },
                  "ref": {
                    "type": "string",
                    "description": "Git ref to associate with the SARIF upload."
                  },
                  "commit_sha": {
                    "type": "string",
                    "description": "40-character commit SHA. If omitted, Strix resolves it from `ref`."
                  },
                  "checkout_uri": {
                    "description": "Repository checkout URI recorded in the SARIF upload so GitHub can map file paths.",
                    "type": "string",
                    "format": "uri"
                  },
                  "github_api_base_url": {
                    "type": "string",
                    "format": "uri",
                    "description": "Override GitHub API base URL for GitHub Enterprise Server."
                  }
                },
                "additionalProperties": false
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "GitHub SARIF upload result.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "repository": {
                      "type": "string"
                    },
                    "ref": {
                      "type": "string"
                    },
                    "commit_sha": {
                      "type": "string"
                    },
                    "sarif_upload": {
                      "type": "object"
                    },
                    "result_count": {
                      "type": "integer"
                    },
                    "code_owner_patterns": {
                      "type": "integer"
                    }
                  },
                  "required": [
                    "repository",
                    "ref",
                    "commit_sha",
                    "sarif_upload",
                    "result_count",
                    "code_owner_patterns"
                  ]
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        }
      }
    },
    "/audit": {
      "get": {
        "operationId": "listAuditEvents",
        "summary": "List audit events",
        "description": "Returns enterprise audit events for the authenticated organization, with optional CSV, Snowflake NDJSON, or Splunk NDJSON export formats.",
        "tags": ["Audit"],
        "security": [
          {
            "BearerAuth": ["audit:read"]
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/Page"
          },
          {
            "description": "Maximum number of events per page. The default is 50 and the maximum is 1000.",
            "name": "limit",
            "in": "query",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 1000,
              "default": 50
            }
          },
          {
            "description": "Return only events with this action name, for example `scan.created`.",
            "name": "action",
            "in": "query",
            "schema": {
              "type": "string"
            }
          },
          {
            "description": "Return only events about this resource type, for example `scan` or `vulnerability`.",
            "name": "resource_type",
            "in": "query",
            "schema": {
              "type": "string"
            }
          },
          {
            "description": "Return only events performed by this actor (user or token) ID.",
            "name": "actor_id",
            "in": "query",
            "schema": {
              "type": "string"
            }
          },
          {
            "description": "Return only events that occurred at or after this time (ISO 8601).",
            "name": "date_from",
            "in": "query",
            "schema": {
              "type": "string",
              "format": "date-time"
            }
          },
          {
            "name": "date_to",
            "in": "query",
            "description": "Plain YYYY-MM-DD values include the full UTC day. Full ISO datetimes are exact upper bounds.",
            "schema": {
              "type": "string"
            }
          },
          {
            "description": "Response format. `json` returns a paginated JSON page. The other values return a file export of matching events.",
            "name": "format",
            "in": "query",
            "schema": {
              "type": "string",
              "enum": ["json", "csv", "ndjson", "jsonl", "snowflake", "splunk"],
              "default": "json"
            }
          },
          {
            "name": "all",
            "in": "query",
            "description": "When true with an export format, stream all matching audit events instead of a single page.",
            "schema": {
              "type": "boolean",
              "default": false
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Audit events or an audit export.",
            "headers": {
              "X-Total-Count": {
                "schema": {
                  "type": "integer"
                }
              },
              "X-Page": {
                "schema": {
                  "type": "integer"
                }
              },
              "X-Limit": {
                "schema": {
                  "type": "integer"
                }
              },
              "X-Total-Pages": {
                "schema": {
                  "type": "integer"
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "type": "array",
                      "items": {
                        "type": "object"
                      }
                    },
                    "pagination": {
                      "$ref": "#/components/schemas/Pagination"
                    }
                  },
                  "required": ["data", "pagination"]
                }
              },
              "text/csv": {
                "schema": {
                  "type": "string"
                }
              },
              "application/x-ndjson": {
                "schema": {
                  "type": "string"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        }
      }
    },
    "/vulnerabilities": {
      "get": {
        "operationId": "listVulnerabilities",
        "summary": "List vulnerabilities",
        "description": "Returns a paginated list of vulnerabilities across all scans for the organization. Set the finding_type query parameter to dependency to read dependency findings. This filter also requires the dependencies:read scope.",
        "tags": ["Vulnerabilities"],
        "security": [
          {
            "BearerAuth": ["vulnerabilities:read"]
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/Page"
          },
          {
            "$ref": "#/components/parameters/Limit"
          },
          {
            "name": "scan_id",
            "in": "query",
            "description": "Filter by scan ID.",
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          },
          {
            "description": "Return only findings with this severity.",
            "name": "severity",
            "in": "query",
            "schema": {
              "$ref": "#/components/schemas/VulnerabilitySeverity"
            }
          },
          {
            "description": "Return only findings in this status.",
            "name": "status",
            "in": "query",
            "schema": {
              "$ref": "#/components/schemas/VulnerabilityStatus"
            }
          },
          {
            "name": "search",
            "in": "query",
            "description": "Full-text search across titles, targets, and STRIX display numbers.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "from",
            "in": "query",
            "description": "Filter by scan created_at >= this date.",
            "schema": {
              "type": "string",
              "format": "date-time"
            }
          },
          {
            "name": "to",
            "in": "query",
            "description": "Filter by scan created_at <= this date.",
            "schema": {
              "type": "string",
              "format": "date-time"
            }
          },
          {
            "description": "Return only the findings of this domain. The response also includes historical findings that have no domain attribution.",
            "name": "domain_id",
            "in": "query",
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          },
          {
            "name": "repository_id",
            "in": "query",
            "description": "Return only the findings of this repository. The response also includes historical findings that have no repository attribution.",
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          },
          {
            "name": "finding_type",
            "in": "query",
            "required": false,
            "description": "Filter by issue type: dynamic findings from live pentests, code review findings, or dependency CVE findings. Omit for all dynamic findings (dependency findings are only returned when explicitly selected). `dependency` additionally requires the `dependencies:read` scope.",
            "schema": {
              "type": "string",
              "enum": ["live_pentest", "code", "dependency"]
            }
          },
          {
            "name": "dependency_relation",
            "in": "query",
            "required": false,
            "description": "Filter dependency findings by how the vulnerable package enters the project. `direct` returns packages that a manifest declares. `transitive` returns packages that another package pulls in. Only applies when `finding_type` is `dependency`.",
            "schema": {
              "type": "string",
              "enum": ["direct", "transitive"]
            }
          },
          {
            "name": "reachability",
            "in": "query",
            "required": false,
            "description": "Filter dependency findings by the usage levels that the scan proved for the vulnerable code. Supply one level, or a comma-separated list of levels. The level `unknown` also returns the findings without a recorded usage level. This filter applies only when `finding_type` is `dependency`. The allowed levels are `reachable_call_path`, `vulnerable_symbol_used`, `imported`, `not_imported`, and `unknown`.",
            "schema": {
              "type": "string",
              "examples": [
                "reachable_call_path",
                "reachable_call_path,vulnerable_symbol_used,imported,unknown"
              ]
            }
          },
          {
            "name": "sort_by",
            "in": "query",
            "description": "The sort key. The key `package` applies only when `finding_type` is `dependency`. For a dependency finding, `cvss` is the score that the scan gave the risk in this codebase. The key `severity` sorts by the CVSS score, and `sort_order=desc` puts the most severe findings first. A finding without a score, or with a severity override, sorts by its severity level.",
            "schema": {
              "type": "string",
              "enum": ["cvss", "created_at", "severity", "package"]
            }
          },
          {
            "$ref": "#/components/parameters/SortOrder"
          }
        ],
        "responses": {
          "200": {
            "description": "Paginated list of vulnerabilities.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PaginatedResponse_VulnerabilitySummary"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        }
      }
    },
    "/vulnerabilities/{vulnerabilityId}": {
      "get": {
        "operationId": "getVulnerability",
        "summary": "Get vulnerability details",
        "description": "Returns full details for a single vulnerability.",
        "tags": ["Vulnerabilities"],
        "security": [
          {
            "BearerAuth": ["vulnerabilities:read"]
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/VulnerabilityId"
          }
        ],
        "responses": {
          "200": {
            "description": "Vulnerability details.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Vulnerability"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        }
      },
      "patch": {
        "operationId": "updateVulnerability",
        "summary": "Update vulnerability status or severity",
        "description": "Change the status and/or severity of a vulnerability. At least one of `status` or `severity` must be provided.",
        "tags": ["Vulnerabilities"],
        "security": [
          {
            "BearerAuth": ["vulnerabilities:write"]
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/VulnerabilityId"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UpdateVulnerabilityRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Updated vulnerability.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Vulnerability"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        }
      }
    },
    "/vulnerabilities/{vulnerabilityId}/http-exchanges": {
      "get": {
        "operationId": "listVulnerabilityHttpExchanges",
        "summary": "List captured HTTP exchanges",
        "description": "Returns the HTTP request metadata that supports a vulnerability. Set `include_content` to `true` to include stored request and response text.",
        "tags": ["Vulnerabilities"],
        "security": [
          {
            "BearerAuth": ["vulnerabilities:read"]
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/VulnerabilityId"
          },
          {
            "name": "include_content",
            "in": "query",
            "description": "Includes stored request and response text when true.",
            "schema": {
              "type": "boolean",
              "default": false
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Captured HTTP exchanges.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/VulnerabilityHttpExchangesResponse"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        }
      }
    },
    "/domains": {
      "get": {
        "operationId": "listDomains",
        "summary": "List domains",
        "description": "Returns a paginated list of domains for the authenticated organization.",
        "tags": ["Assets"],
        "security": [
          {
            "BearerAuth": ["assets:read"]
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/Page"
          },
          {
            "description": "Maximum number of items per page. The default is 25 and the maximum is 100.",
            "name": "limit",
            "in": "query",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 100,
              "default": 25
            }
          },
          {
            "name": "search",
            "in": "query",
            "description": "Filter domains by name (case-insensitive substring match).",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "verified",
            "in": "query",
            "description": "Filter by verification status.",
            "schema": {
              "type": "string",
              "enum": ["true", "false"]
            }
          },
          {
            "name": "business_unit",
            "in": "query",
            "description": "Filter by exact business_unit (Enterprise asset label).",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "tags",
            "in": "query",
            "description": "Comma-separated tags. Returns the domains that have all of the supplied tags.",
            "schema": {
              "type": "string"
            }
          },
          {
            "description": "Field to sort by. `last_scan_at` orders by the most recent scan.",
            "name": "sort_by",
            "in": "query",
            "schema": {
              "type": "string",
              "enum": ["created_at", "last_scan_at"],
              "default": "created_at"
            }
          },
          {
            "$ref": "#/components/parameters/SortOrder"
          }
        ],
        "responses": {
          "200": {
            "description": "Paginated list of domains.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PaginatedResponse_Domain"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        }
      },
      "post": {
        "operationId": "createDomain",
        "summary": "Add a domain",
        "description": "Register a domain asset for the authenticated organization and return verification instructions.",
        "tags": ["Assets"],
        "security": [
          {
            "BearerAuth": ["assets:write"]
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreateDomainRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Domain already exists.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DomainCreateResponse"
                }
              }
            }
          },
          "201": {
            "description": "Domain added.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DomainCreateResponse"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "422": {
            "$ref": "#/components/responses/ValidationError"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        }
      }
    },
    "/repositories": {
      "get": {
        "operationId": "listRepositories",
        "summary": "List repositories",
        "description": "Returns a paginated list of repositories for the authenticated organization.",
        "tags": ["Assets"],
        "security": [
          {
            "BearerAuth": ["assets:read"]
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/Page"
          },
          {
            "description": "Maximum number of items per page. The default is 25 and the maximum is 100.",
            "name": "limit",
            "in": "query",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 100,
              "default": 25
            }
          },
          {
            "name": "search",
            "in": "query",
            "description": "Filter repositories by full name (case-insensitive substring match).",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "business_unit",
            "in": "query",
            "description": "Filter by exact business_unit (Enterprise asset label).",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "tags",
            "in": "query",
            "description": "Comma-separated tags. Returns the repositories that have all of the supplied tags.",
            "schema": {
              "type": "string"
            }
          },
          {
            "description": "Field to sort by. `last_scan_at` orders by the most recent scan.",
            "name": "sort_by",
            "in": "query",
            "schema": {
              "type": "string",
              "enum": ["created_at", "last_scan_at"],
              "default": "created_at"
            }
          },
          {
            "$ref": "#/components/parameters/SortOrder"
          }
        ],
        "responses": {
          "200": {
            "description": "Paginated list of repositories.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PaginatedResponse_Repository"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        }
      },
      "post": {
        "operationId": "createRepositories",
        "summary": "Add repositories",
        "description": "Register one or more repository assets for the authenticated organization.",
        "tags": ["Assets"],
        "security": [
          {
            "BearerAuth": ["assets:write"]
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "description": "One repository object, or an array of repository objects to add in one request.",
                "oneOf": [
                  {
                    "$ref": "#/components/schemas/CreateRepositoryRequest"
                  },
                  {
                    "type": "array",
                    "items": {
                      "$ref": "#/components/schemas/CreateRepositoryRequest"
                    }
                  }
                ]
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Repositories added.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/RepositoriesCreateResponse"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        }
      }
    },
    "/schedules": {
      "get": {
        "operationId": "listSchedules",
        "summary": "List schedules",
        "description": "Returns all scan schedules for the organization. Requires Pro plan.",
        "tags": ["Schedules"],
        "security": [
          {
            "BearerAuth": ["schedules:read"]
          }
        ],
        "responses": {
          "200": {
            "description": "List of schedules.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "schedules": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/ScanSchedule"
                      }
                    }
                  },
                  "required": ["schedules"]
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/TierLimitError"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        }
      },
      "post": {
        "operationId": "createSchedule",
        "summary": "Create a schedule",
        "description": "Create a recurring scan schedule. Optionally trigger an immediate scan with `also_run_now`. Supply Chain schedules require the Enterprise Supply Chain entitlement. When `also_run_now` creates a chargeable scan, the optional Idempotency-Key covers both schedule creation and that immediate scan; reuse the exact same key only to retry the exact same request. Replay and in-progress responses are still subject to current authorization against the persisted schedule when it exists.",
        "tags": ["Schedules"],
        "security": [
          {
            "BearerAuth": ["schedules:write"]
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreateScheduleRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Schedule created.",
            "headers": {
              "Idempotency-Key": {
                "$ref": "#/components/headers/IdempotencyKeyResponse"
              },
              "Idempotency-Replayed": {
                "$ref": "#/components/headers/IdempotencyReplayed"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "schedule_id": {
                      "type": "string"
                    },
                    "name": {
                      "type": "string"
                    },
                    "scan_id": {
                      "type": ["string", "null"],
                      "description": "Set when also_run_now was true and scan launched successfully."
                    },
                    "scan_error": {
                      "type": ["string", "null"]
                    }
                  },
                  "required": ["schedule_id", "name"]
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/IdempotencyBadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "402": {
            "$ref": "#/components/responses/PaymentRequired"
          },
          "403": {
            "description": "The plan or Enterprise Supply Chain entitlement does not allow this request.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TierLimitErrorResponse"
                }
              }
            }
          },
          "409": {
            "$ref": "#/components/responses/IdempotencyConflictOrInProgress"
          },
          "503": {
            "$ref": "#/components/responses/IdempotencyOutcomeUnknown"
          },
          "500": {
            "$ref": "#/components/responses/IdempotencyInternalOrAbandoned"
          }
        }
      }
    },
    "/schedules/{scheduleId}": {
      "get": {
        "operationId": "getSchedule",
        "summary": "Get schedule details",
        "description": "Returns schedule details including recent run history.",
        "tags": ["Schedules"],
        "security": [
          {
            "BearerAuth": ["schedules:read"]
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/ScheduleId"
          }
        ],
        "responses": {
          "200": {
            "description": "Schedule details with runs.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/ScanSchedule"
                    },
                    {
                      "type": "object",
                      "properties": {
                        "runs": {
                          "type": "array",
                          "items": {
                            "$ref": "#/components/schemas/ScheduleRun"
                          }
                        }
                      }
                    }
                  ]
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/TierLimitError"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        }
      },
      "patch": {
        "operationId": "updateSchedule",
        "summary": "Update a schedule",
        "description": "Update a schedule's configuration, cron expression, or pause/resume it. Send `action: \"pause\"` or `action: \"resume\"` to toggle, or provide fields to update.",
        "tags": ["Schedules"],
        "security": [
          {
            "BearerAuth": ["schedules:write"]
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/ScheduleId"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UpdateScheduleRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Schedule updated.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    },
                    "isPaused": {
                      "type": "boolean"
                    }
                  },
                  "required": ["success"]
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/TierLimitError"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        }
      },
      "delete": {
        "operationId": "deleteSchedule",
        "summary": "Delete a schedule",
        "tags": ["Schedules"],
        "security": [
          {
            "BearerAuth": ["schedules:write"]
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/ScheduleId"
          }
        ],
        "responses": {
          "200": {
            "description": "Schedule deleted.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SuccessResponse"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/TierLimitError"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        }
      }
    },
    "/schedules/{scheduleId}/trigger": {
      "post": {
        "operationId": "triggerSchedule",
        "summary": "Trigger a schedule immediately",
        "description": "Trigger an immediate run of a scheduled scan. Stored Supply Chain schedules require the Enterprise Supply Chain entitlement. A 200 acknowledges durable queue acceptance; later execution failures are reported in the schedule's run health and are never silently launched a second time. Manual schedule fires support the optional Idempotency-Key contract used by scan creation: reuse the exact same key only to retry the same schedule trigger after a lost or ambiguous response. Replay and in-progress responses are returned only after current authorization against the schedule succeeds.",
        "tags": ["Schedules"],
        "security": [
          {
            "BearerAuth": ["schedules:write"]
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/ScheduleId"
          },
          {
            "$ref": "#/components/parameters/IdempotencyKey"
          }
        ],
        "responses": {
          "200": {
            "description": "The manual fire was durably accepted by the queue. This does not assert that the asynchronously launched scan has completed successfully.",
            "headers": {
              "Idempotency-Key": {
                "$ref": "#/components/headers/IdempotencyKeyResponse"
              },
              "Idempotency-Replayed": {
                "$ref": "#/components/headers/IdempotencyReplayed"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SuccessResponse"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/IdempotencyBadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "402": {
            "$ref": "#/components/responses/PaymentRequired"
          },
          "403": {
            "description": "The plan or Enterprise Supply Chain entitlement does not allow this request.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TierLimitErrorResponse"
                }
              }
            }
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "$ref": "#/components/responses/IdempotencyConflictOrInProgress"
          },
          "503": {
            "$ref": "#/components/responses/IdempotencyOutcomeUnknown"
          },
          "500": {
            "$ref": "#/components/responses/IdempotencyInternalOrAbandoned"
          }
        }
      }
    },
    "/schedules/{scheduleId}/template": {
      "get": {
        "operationId": "getScheduleTemplate",
        "summary": "Get a schedule's editable configuration",
        "description": "Returns the full stored configuration of the schedule, in a format that you can edit with PATCH /schedules/{scheduleId} — targets, prompts, test users, headers, scope, timing, notifications, and uploads. Credentials are returned as metadata only (username, notes, MFA method, has_stored_secret) and headers as metadata only (name, notes, has_stored_value) — raw secrets such as passwords, TOTP seeds, header values, MFA inboxes, and login URLs are never included. Keep a stored header value on PATCH by sending keep_stored_value: true.",
        "tags": ["Schedules"],
        "security": [
          {
            "BearerAuth": ["schedules:read"]
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/ScheduleId"
          }
        ],
        "responses": {
          "200": {
            "description": "Schedule template.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": true
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        }
      }
    },
    "/tokens": {
      "get": {
        "operationId": "listTokens",
        "summary": "List API tokens",
        "description": "List API tokens visible to the authenticated user. Admins see all tokens. Non-admins see only their own personal tokens. Asset-scoped tokens cannot access organization-wide token management.",
        "tags": ["Tokens"],
        "security": [
          {
            "BearerAuth": ["tokens:write"]
          }
        ],
        "parameters": [
          {
            "name": "type",
            "in": "query",
            "description": "Filter by token type.",
            "schema": {
              "type": "string",
              "enum": ["service", "personal"]
            }
          }
        ],
        "responses": {
          "200": {
            "description": "List of tokens.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "tokens": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/ApiToken"
                      }
                    }
                  },
                  "required": ["tokens"]
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        }
      },
      "post": {
        "operationId": "createToken",
        "summary": "Create an API token",
        "description": "Create a new service or personal API token. The raw token secret is returned only in this response. Asset-scoped tokens cannot access organization-wide token management.",
        "tags": ["Tokens"],
        "security": [
          {
            "BearerAuth": ["tokens:write"]
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreateTokenRequest"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Token created. The `token` field contains the raw secret — store it securely.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "token": {
                      "type": "string",
                      "description": "Raw API token secret. Only returned at creation time."
                    },
                    "token_record": {
                      "$ref": "#/components/schemas/ApiToken"
                    }
                  },
                  "required": ["token", "token_record"]
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        }
      }
    },
    "/tokens/{tokenId}": {
      "delete": {
        "operationId": "revokeToken",
        "summary": "Revoke an API token",
        "tags": ["Tokens"],
        "security": [
          {
            "BearerAuth": ["tokens:write"]
          }
        ],
        "parameters": [
          {
            "description": "UUID of the API token. Use the `id` field of a token from `listTokens`.",
            "name": "tokenId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Token revoked.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SuccessResponse"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        },
        "description": "Revoke an API token. Asset-scoped tokens cannot access organization-wide token management."
      }
    },
    "/webhooks": {
      "get": {
        "operationId": "listWebhooks",
        "summary": "List webhooks",
        "description": "Returns webhooks for the organization. Asset-scoped tokens see only subscriptions whose business_unit is covered by their token scopes.",
        "tags": ["Webhooks"],
        "security": [
          {
            "BearerAuth": ["webhooks:read"]
          }
        ],
        "responses": {
          "200": {
            "description": "List of webhooks.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "webhooks": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/Webhook"
                      }
                    }
                  },
                  "required": ["webhooks"]
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        }
      },
      "post": {
        "operationId": "createWebhook",
        "summary": "Create a webhook",
        "description": "Create a new webhook subscription. The signing `secret` is returned only in this response. Asset-scoped tokens must provide an in-scope business_unit and cannot create organization-wide subscriptions.",
        "tags": ["Webhooks"],
        "security": [
          {
            "BearerAuth": ["webhooks:write"]
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreateWebhookRequest"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Webhook created.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "webhook": {
                      "$ref": "#/components/schemas/Webhook"
                    },
                    "secret": {
                      "type": "string",
                      "description": "Webhook signing secret. Only returned at creation time."
                    }
                  },
                  "required": ["webhook", "secret"]
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        }
      }
    },
    "/webhooks/{webhookId}": {
      "patch": {
        "operationId": "updateWebhook",
        "summary": "Update a webhook",
        "description": "Update webhook URL, events, active status, or rotate the signing secret. Asset-scoped tokens may update only an in-scope business_unit webhook. If you omit business_unit, the webhook keeps its current business_unit. If you change business_unit, use an in-scope value.",
        "tags": ["Webhooks"],
        "security": [
          {
            "BearerAuth": ["webhooks:write"]
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/WebhookId"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UpdateWebhookRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Webhook updated. Includes `secret` if `rotate_secret` was true.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "webhook": {
                      "$ref": "#/components/schemas/Webhook"
                    },
                    "secret": {
                      "type": "string",
                      "description": "New signing secret, only present when rotate_secret was true."
                    }
                  },
                  "required": ["webhook"]
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        }
      },
      "delete": {
        "operationId": "deleteWebhook",
        "summary": "Delete a webhook",
        "tags": ["Webhooks"],
        "security": [
          {
            "BearerAuth": ["webhooks:write"]
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/WebhookId"
          }
        ],
        "responses": {
          "200": {
            "description": "Webhook deleted.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SuccessResponse"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        },
        "description": "Delete a webhook. Asset-scoped tokens may delete only a webhook whose business_unit is covered by their token scopes."
      },
      "get": {
        "operationId": "getWebhook",
        "summary": "Get a webhook",
        "description": "Returns a webhook subscription. Asset-scoped tokens may access only a webhook whose business_unit is covered by their token scopes.",
        "tags": ["Webhooks"],
        "security": [
          {
            "BearerAuth": ["webhooks:read"]
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/WebhookId"
          }
        ],
        "responses": {
          "200": {
            "description": "Webhook subscription.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "webhook": {
                      "$ref": "#/components/schemas/Webhook"
                    }
                  },
                  "required": ["webhook"]
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        }
      }
    },
    "/webhooks/{webhookId}/deliveries": {
      "get": {
        "operationId": "listWebhookDeliveries",
        "summary": "List webhook deliveries",
        "description": "Returns a paginated delivery log for a specific webhook. Asset-scoped tokens may access deliveries only for an in-scope business_unit webhook.",
        "tags": ["Webhooks"],
        "security": [
          {
            "BearerAuth": ["webhooks:read"]
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/WebhookId"
          },
          {
            "$ref": "#/components/parameters/Page"
          },
          {
            "$ref": "#/components/parameters/Limit"
          }
        ],
        "responses": {
          "200": {
            "description": "Paginated delivery log.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PaginatedResponse_WebhookDelivery"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        }
      }
    },
    "/domains/{domainId}": {
      "patch": {
        "operationId": "updateDomain",
        "summary": "Update a domain",
        "description": "Update a domain's context, tags, or business_unit. Tags and business_unit require the Enterprise plan.",
        "tags": ["Assets"],
        "security": [
          {
            "BearerAuth": ["assets:write"]
          }
        ],
        "parameters": [
          {
            "description": "UUID of the domain. Use the `id` field of a domain from `listDomains`.",
            "name": "domainId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UpdateDomainRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Domain updated.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Domain"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        }
      },
      "delete": {
        "operationId": "deleteDomain",
        "summary": "Remove a domain",
        "tags": ["Assets"],
        "security": [
          {
            "BearerAuth": ["assets:write"]
          }
        ],
        "parameters": [
          {
            "description": "UUID of the domain. Use the `id` field of a domain from `listDomains`.",
            "name": "domainId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Domain removed.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    }
                  },
                  "required": ["success"]
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        }
      }
    },
    "/domains/{domainId}/verify": {
      "post": {
        "operationId": "verifyDomain",
        "summary": "Verify a domain",
        "description": "Checks DNS, verification file, meta tag, allowlist, and existing organization verification methods.",
        "tags": ["Assets"],
        "security": [
          {
            "BearerAuth": ["assets:write"]
          }
        ],
        "parameters": [
          {
            "description": "UUID of the domain. Use the `id` field of a domain from `listDomains`.",
            "name": "domainId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Verification result. A 200 status does not mean success. When `verified` is false, `status` is `pending` and `next_steps` lists the records to add.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DomainVerificationResponse"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        }
      }
    },
    "/domains/{domainId}/auto-verify": {
      "post": {
        "operationId": "autoVerifyDomain",
        "summary": "Verify a domain through a connected DNS provider",
        "description": "Creates the _strix-verification TXT record through the organization's connected DNS provider (Vercel or Cloudflare) and runs the DNS verification check. Requires an organization admin to have connected the provider in the dashboard first.",
        "tags": ["Assets"],
        "security": [
          {
            "BearerAuth": ["assets:write"]
          }
        ],
        "parameters": [
          {
            "description": "UUID of the domain. Use the `id` field of a domain from `listDomains`.",
            "name": "domainId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": ["provider"],
                "properties": {
                  "provider": {
                    "type": "string",
                    "enum": ["vercel", "cloudflare"],
                    "description": "Connected DNS provider to create the verification record with."
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Auto-verification result.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "domain": {
                      "$ref": "#/components/schemas/Domain"
                    },
                    "verified": {
                      "type": "boolean"
                    },
                    "record_created": {
                      "type": "boolean",
                      "description": "Whether the verification TXT record was created (or already existed) at the provider."
                    },
                    "error": {
                      "type": "string",
                      "description": "Human-readable reason when verification did not complete."
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        }
      }
    },
    "/repositories/{repositoryId}": {
      "patch": {
        "operationId": "updateRepository",
        "summary": "Update repository settings",
        "tags": ["Assets"],
        "security": [
          {
            "BearerAuth": ["assets:write"]
          }
        ],
        "parameters": [
          {
            "description": "UUID of the repository. Use the `id` field of a repository from `listRepositories`.",
            "name": "repositoryId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UpdateRepositoryRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Repository updated.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/RepositoryAsset"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        }
      },
      "delete": {
        "operationId": "deleteRepository",
        "summary": "Remove a repository",
        "tags": ["Assets"],
        "security": [
          {
            "BearerAuth": ["assets:write"]
          }
        ],
        "parameters": [
          {
            "description": "UUID of the repository. Use the `id` field of a repository from `listRepositories`.",
            "name": "repositoryId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Repository removed.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    }
                  },
                  "required": ["success"]
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        }
      }
    },
    "/organization": {
      "get": {
        "operationId": "getOrganization",
        "summary": "Get organization",
        "description": "Returns workspace configuration for the authenticated token organization.",
        "tags": ["Organization"],
        "security": [
          {
            "BearerAuth": ["organizations:read"]
          }
        ],
        "responses": {
          "200": {
            "description": "Organization details.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Organization"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        }
      },
      "patch": {
        "operationId": "updateOrganization",
        "summary": "Update organization",
        "description": "Rename the authenticated token organization.",
        "tags": ["Organization"],
        "security": [
          {
            "BearerAuth": ["organizations:write"]
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UpdateOrganizationRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Organization updated.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Organization"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        }
      }
    },
    "/organization/members": {
      "get": {
        "operationId": "listOrganizationMembers",
        "summary": "List organization members",
        "tags": ["Members"],
        "security": [
          {
            "BearerAuth": ["members:read"]
          }
        ],
        "responses": {
          "200": {
            "description": "Organization members.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/MembersListResponse"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        }
      },
      "post": {
        "operationId": "inviteOrganizationMember",
        "summary": "Invite organization member",
        "tags": ["Members"],
        "security": [
          {
            "BearerAuth": ["members:write"]
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/InviteMemberRequest"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Invitation created.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Invitation"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        }
      }
    },
    "/organization/members/{membershipId}": {
      "patch": {
        "operationId": "updateOrganizationMemberRole",
        "summary": "Update member role",
        "tags": ["Members"],
        "security": [
          {
            "BearerAuth": ["members:write"]
          }
        ],
        "parameters": [
          {
            "description": "ID of the membership. Use the `id` field of a member from `listOrganizationMembers`.",
            "name": "membershipId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UpdateMemberRoleRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Member role updated.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/MemberRoleUpdateResponse"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        }
      },
      "delete": {
        "operationId": "removeOrganizationMember",
        "summary": "Remove member",
        "tags": ["Members"],
        "security": [
          {
            "BearerAuth": ["members:write"]
          }
        ],
        "parameters": [
          {
            "description": "ID of the membership. Use the `id` field of a member from `listOrganizationMembers`.",
            "name": "membershipId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Member removed.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "message": {
                      "type": "string"
                    }
                  },
                  "required": ["message"]
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        }
      }
    },
    "/organization/invitations": {
      "get": {
        "operationId": "listOrganizationInvitations",
        "summary": "List pending invitations",
        "tags": ["Invitations"],
        "security": [
          {
            "BearerAuth": ["invitations:read"]
          }
        ],
        "responses": {
          "200": {
            "description": "Organization invitations.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/InvitationsListResponse"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        }
      }
    },
    "/organization/invitations/{invitationId}": {
      "delete": {
        "operationId": "revokeOrganizationInvitation",
        "summary": "Revoke invitation",
        "tags": ["Invitations"],
        "security": [
          {
            "BearerAuth": ["invitations:write"]
          }
        ],
        "parameters": [
          {
            "description": "ID of the pending invitation. Use the `id` field of an invitation from `listOrganizationInvitations`.",
            "name": "invitationId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Invitation revoked.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "message": {
                      "type": "string"
                    }
                  },
                  "required": ["message"]
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        }
      }
    },
    "/analytics/stats": {
      "get": {
        "operationId": "getAnalyticsStats",
        "summary": "Get dashboard analytics",
        "description": "Aggregate counts powering the dashboard (scans, vulnerabilities by severity/status, and more). Accepts the same filter query params as the dashboard. Asset-scoped tokens cannot access organization-wide analytics.",
        "tags": ["Analytics"],
        "security": [
          {
            "BearerAuth": ["analytics:read"]
          }
        ],
        "responses": {
          "200": {
            "description": "Dashboard statistics.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": true
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        }
      }
    },
    "/analytics/overview": {
      "get": {
        "operationId": "getAnalyticsOverview",
        "summary": "Get dashboard overview",
        "description": "Unified dashboard overview: KPIs with period-over-period deltas, issues-over-time by source (pentests vs PR reviews), severity breakdown, PR review effectiveness (distinct PRs, verdicts, addressed rate, top repos and contributors), remediation trends, exploitability (KEV/EPSS) of open issues and active dependency CVEs, threat intelligence feed (recently exploited and high-risk CVEs, flagged when they match your open issues), and activity heatmap. Asset-scoped tokens cannot access organization-wide analytics.",
        "tags": ["Analytics"],
        "parameters": [
          {
            "description": "Time window of the overview. Use `custom` together with explicit start and end dates.",
            "name": "range",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "enum": ["7d", "30d", "90d", "all", "custom"],
              "default": "30d"
            }
          },
          {
            "name": "from",
            "in": "query",
            "required": false,
            "description": "Start date (ISO 8601), used when range=custom.",
            "schema": {
              "type": "string",
              "format": "date"
            }
          },
          {
            "name": "to",
            "in": "query",
            "required": false,
            "description": "End date (ISO 8601), used when range=custom.",
            "schema": {
              "type": "string",
              "format": "date"
            }
          }
        ],
        "security": [
          {
            "BearerAuth": ["analytics:read"]
          }
        ],
        "responses": {
          "200": {
            "description": "Dashboard overview.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": true
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          },
          "503": {
            "$ref": "#/components/responses/ServiceUnavailable"
          }
        }
      }
    },
    "/llm-costs": {
      "get": {
        "operationId": "getLlmCostsOverview",
        "summary": "Get LLM costs overview",
        "description": "Self-hosted (on-prem) only — returns 404 on SaaS. Full LLM spend analytics: KPIs with period deltas, month-to-date and projected burn, cost and token timelines, breakdowns by model/asset/member, most expensive runs, and cache efficiency. Requires an unrestricted token (tokens limited by rbac scopes are rejected).",
        "tags": ["LLM"],
        "parameters": [
          {
            "description": "Time window of the cost report. Use `custom` together with explicit start and end dates.",
            "name": "range",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "enum": ["7d", "30d", "90d", "all", "custom"],
              "default": "30d"
            }
          },
          {
            "name": "from",
            "in": "query",
            "required": false,
            "description": "Start date (ISO 8601), used when range=custom.",
            "schema": {
              "type": "string",
              "format": "date"
            }
          },
          {
            "name": "to",
            "in": "query",
            "required": false,
            "description": "End date (ISO 8601), used when range=custom.",
            "schema": {
              "type": "string",
              "format": "date"
            }
          }
        ],
        "security": [
          {
            "BearerAuth": ["llm:read"]
          }
        ],
        "responses": {
          "200": {
            "description": "LLM costs overview.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": true
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        }
      }
    },
    "/llm-costs/runs/{runType}/{runId}": {
      "get": {
        "operationId": "getRunLlmUsage",
        "summary": "Get LLM usage for a run",
        "description": "Self-hosted (on-prem) only — returns 404 on SaaS. Cost, token, and request totals recorded for a single scan, PR review, or chat run. `usage` is null until the run has reported cost. Requires an unrestricted token (tokens limited by rbac scopes are rejected).",
        "tags": ["LLM"],
        "parameters": [
          {
            "description": "Kind of run to look up.",
            "name": "runType",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "enum": ["scan", "pr_review", "chat"]
            }
          },
          {
            "description": "ID of the scan, PR review, or chat run.",
            "name": "runId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "security": [
          {
            "BearerAuth": ["llm:read"]
          }
        ],
        "responses": {
          "200": {
            "description": "Per-run LLM usage (null when not yet recorded).",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "usage": {
                      "type": ["object", "null"],
                      "additionalProperties": true
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        }
      }
    },
    "/llm-settings": {
      "get": {
        "operationId": "getLlmSettings",
        "summary": "Get LLM model settings",
        "description": "Self-hosted (on-prem) only — returns 404 on SaaS. Requires the organization admin role. Named model configurations (API keys and extra headers are never returned, only whether they are set), per-purpose model assignments (default, scan, pr_review, chat, dedupe, app), env-fallback models per purpose, and current month-to-date spend per run type.",
        "tags": ["LLM"],
        "security": [
          {
            "BearerAuth": ["llm:read"]
          }
        ],
        "responses": {
          "200": {
            "description": "LLM settings and month-to-date spend.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "settings": {
                      "type": "object",
                      "additionalProperties": true
                    },
                    "mtdSpend": {
                      "type": "object",
                      "additionalProperties": {
                        "type": "number"
                      }
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        }
      },
      "put": {
        "operationId": "updateLlmSettings",
        "summary": "Update LLM model settings",
        "description": "Self-hosted (on-prem) only — returns 404 on SaaS. Requires the organization admin role. Full-state save of model configurations and per-purpose assignments. Include `apiKey` on a model config to set or replace its key (stored encrypted). Omit it to keep the existing key. Same for `extraHeaders` (an empty string clears the stored value).",
        "tags": ["LLM"],
        "security": [
          {
            "BearerAuth": ["llm:write"]
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": ["modelConfigs", "assignments"],
                "properties": {
                  "modelConfigs": {
                    "description": "Full list of model configurations. Configurations that are not in the list are deleted.",
                    "type": "array",
                    "items": {
                      "type": "object",
                      "required": ["id", "name", "model"],
                      "properties": {
                        "id": {
                          "type": "string",
                          "description": "Existing config id, or any placeholder id for a new config."
                        },
                        "name": {
                          "type": "string"
                        },
                        "model": {
                          "type": "string",
                          "description": "LiteLLM provider/model identifier."
                        },
                        "apiKey": {
                          "type": "string",
                          "description": "Set or replace the API key. Omit to keep the existing key, which only happens while apiBaseUrl is unchanged."
                        },
                        "apiBaseUrl": {
                          "type": "string",
                          "description": "Destination the stored credentials belong to. Changing it (including omitting it for a config that has one) deletes the stored API key and extra headers unless replacements are sent in the same request."
                        },
                        "extraHeaders": {
                          "type": "string",
                          "description": "JSON object of extra request headers, stored encrypted. Omit to keep the existing value while apiBaseUrl is unchanged. Send an empty string to clear it."
                        },
                        "timeoutSeconds": {
                          "type": ["integer", "null"]
                        },
                        "reasoningEffort": {
                          "type": ["string", "null"],
                          "enum": [
                            "none",
                            "minimal",
                            "low",
                            "medium",
                            "high",
                            "xhigh",
                            null
                          ]
                        },
                        "promptCache": {
                          "type": ["boolean", "null"]
                        },
                        "disableStreaming": {
                          "type": ["boolean", "null"]
                        },
                        "contextFallbackTokens": {
                          "type": ["integer", "null"]
                        },
                        "inputCostPerMTok": {
                          "type": ["number", "null"],
                          "minimum": 0,
                          "description": "Custom input price in USD per 1M tokens. When any custom price is set, Strix computes run costs from these rates instead of the automatic estimate."
                        },
                        "outputCostPerMTok": {
                          "type": ["number", "null"],
                          "minimum": 0,
                          "description": "Custom output price in USD per 1M tokens."
                        },
                        "cachedInputCostPerMTok": {
                          "type": ["number", "null"],
                          "minimum": 0,
                          "description": "Custom cached-input price in USD per 1M tokens. When not set, cached input tokens use the input price."
                        }
                      }
                    }
                  },
                  "assignments": {
                    "type": "object",
                    "description": "Named config assigned to each purpose (config id or null). Unassigned purposes fall back to `default`, then to the deployment's STRIX_LLM_* environment.",
                    "properties": {
                      "default": {
                        "type": ["string", "null"]
                      },
                      "scan": {
                        "type": ["string", "null"]
                      },
                      "pr_review": {
                        "type": ["string", "null"]
                      },
                      "chat": {
                        "type": ["string", "null"]
                      },
                      "dedupe": {
                        "type": ["string", "null"]
                      },
                      "app": {
                        "type": ["string", "null"]
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Persisted settings (server-assigned config ids, apiKeySet flags).",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "settings": {
                      "type": "object",
                      "additionalProperties": true
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        }
      }
    },
    "/analytics/scan-frequency": {
      "get": {
        "operationId": "getScanFrequency",
        "summary": "Get scan frequency timeline",
        "description": "Daily scan counts for roughly the last 10 months, suitable for a contribution-style heatmap. Asset-scoped tokens cannot access organization-wide analytics.",
        "tags": ["Analytics"],
        "security": [
          {
            "BearerAuth": ["analytics:read"]
          }
        ],
        "parameters": [
          {
            "name": "tz",
            "in": "query",
            "required": false,
            "description": "IANA timezone for day bucketing. Defaults to UTC.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "One entry per calendar day.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/ScanFrequencyDay"
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        }
      }
    },
    "/connectors": {
      "get": {
        "operationId": "listConnectors",
        "summary": "List network connectors",
        "tags": ["Connectors"],
        "security": [
          {
            "BearerAuth": ["connectors:read"]
          }
        ],
        "responses": {
          "200": {
            "description": "Connectors for the organization.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "connectors": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/NetworkConnector"
                      }
                    }
                  },
                  "required": ["connectors"]
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        }
      },
      "post": {
        "operationId": "createConnector",
        "summary": "Create a network connector",
        "description": "Provisions a connector and returns a `docker run` command to start the agent inside the customer network. Requires a tier with network connectors enabled. Personal tokens must belong to an organization admin (parity with the dashboard).",
        "tags": ["Connectors"],
        "security": [
          {
            "BearerAuth": ["connectors:write"]
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreateConnectorRequest"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Connector created.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CreateConnectorResponse"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/TierLimitError"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        }
      }
    },
    "/connectors/{connectorId}": {
      "get": {
        "operationId": "getConnector",
        "summary": "Get a network connector",
        "tags": ["Connectors"],
        "security": [
          {
            "BearerAuth": ["connectors:read"]
          }
        ],
        "parameters": [
          {
            "name": "connectorId",
            "in": "path",
            "required": true,
            "description": "Connector id.",
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          },
          {
            "name": "include_command",
            "in": "query",
            "required": false,
            "description": "When true, include the `docker run` deploy command (contains the connector auth key). Requires the `connectors:write` scope. Personal tokens must belong to an organization admin.",
            "schema": {
              "type": "boolean"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Connector details.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/NetworkConnector"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        }
      },
      "delete": {
        "operationId": "deleteConnector",
        "description": "Deletes the connector and revokes its devices. Personal tokens must belong to an organization admin (parity with the dashboard).",
        "summary": "Delete a network connector",
        "tags": ["Connectors"],
        "security": [
          {
            "BearerAuth": ["connectors:write"]
          }
        ],
        "parameters": [
          {
            "name": "connectorId",
            "in": "path",
            "required": true,
            "description": "Connector id.",
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Connector deleted.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SuccessResponse"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        }
      }
    },
    "/connectors/{connectorId}/status": {
      "get": {
        "operationId": "getConnectorStatus",
        "summary": "Get live connector status",
        "description": "Queries the connector's live health and updates the stored status.",
        "tags": ["Connectors"],
        "security": [
          {
            "BearerAuth": ["connectors:read"]
          }
        ],
        "parameters": [
          {
            "name": "connectorId",
            "in": "path",
            "required": true,
            "description": "Connector id.",
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Current connector status.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "status": {
                      "$ref": "#/components/schemas/ConnectorStatus"
                    }
                  },
                  "additionalProperties": true
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        }
      }
    },
    "/chat": {
      "get": {
        "operationId": "listChats",
        "summary": "List chats",
        "description": "Most recent chats for the organization (up to 50).",
        "tags": ["Chat"],
        "security": [
          {
            "BearerAuth": ["chat:read"]
          }
        ],
        "responses": {
          "200": {
            "description": "Chat list.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "chats": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/ChatSummary"
                      }
                    }
                  },
                  "required": ["chats"]
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        }
      },
      "post": {
        "operationId": "startChat",
        "summary": "Start a chat",
        "description": "Starts a new agent chat. Use `application/json` for text-only, or `multipart/form-data` to attach files (field `files`).",
        "tags": ["Chat"],
        "security": [
          {
            "BearerAuth": ["chat:write"]
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/StartChatRequest"
              }
            },
            "multipart/form-data": {
              "schema": {
                "type": "object",
                "properties": {
                  "message": {
                    "type": "string"
                  },
                  "files": {
                    "type": "array",
                    "items": {
                      "type": "string",
                      "format": "binary"
                    }
                  },
                  "repos": {
                    "type": "string",
                    "description": "JSON-encoded array of {repoId, branch}."
                  },
                  "images": {
                    "type": "string",
                    "description": "JSON-encoded array of {url}."
                  },
                  "domain_ids": {
                    "type": "string",
                    "description": "JSON-encoded array of verified organization domain ids to scope the chat to."
                  }
                },
                "required": ["message"]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Chat started.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": true
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/TierLimitError"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        }
      }
    },
    "/chat/{chatId}": {
      "get": {
        "operationId": "getChat",
        "summary": "Get a chat",
        "tags": ["Chat"],
        "security": [
          {
            "BearerAuth": ["chat:read"]
          }
        ],
        "parameters": [
          {
            "name": "chatId",
            "in": "path",
            "required": true,
            "description": "Chat id.",
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Chat details.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "chat": {
                      "$ref": "#/components/schemas/Chat"
                    }
                  },
                  "required": ["chat"]
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        }
      }
    },
    "/chat/{chatId}/message": {
      "post": {
        "operationId": "sendChatMessage",
        "summary": "Send a chat message",
        "description": "Sends a message to an active chat. Use `application/json` for text-only, or `multipart/form-data` to attach files. `message` may be omitted for a control-only request when `cancel_current` or `stop_agent` is true.",
        "tags": ["Chat"],
        "security": [
          {
            "BearerAuth": ["chat:write"]
          }
        ],
        "parameters": [
          {
            "name": "chatId",
            "in": "path",
            "required": true,
            "description": "Chat id.",
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/SendChatMessageRequest"
              }
            },
            "multipart/form-data": {
              "schema": {
                "type": "object",
                "properties": {
                  "message": {
                    "type": "string",
                    "minLength": 1
                  },
                  "cancel_current": {
                    "type": "string"
                  },
                  "stop_agent": {
                    "type": "string",
                    "description": "\"true\" parks the target agent and its descendants instead of only cancelling the current turn."
                  },
                  "files": {
                    "type": "array",
                    "items": {
                      "type": "string",
                      "format": "binary"
                    }
                  },
                  "repos": {
                    "type": "string",
                    "description": "JSON-encoded array of {repoId, branch}."
                  },
                  "images": {
                    "type": "string",
                    "description": "JSON-encoded array of {url}."
                  },
                  "agent_id": {
                    "type": "string",
                    "description": "Deliver the message to this subagent instead of the chat's root agent."
                  }
                },
                "anyOf": [
                  {
                    "required": ["message"]
                  },
                  {
                    "required": ["cancel_current"],
                    "properties": {
                      "cancel_current": {
                        "const": "true"
                      }
                    }
                  },
                  {
                    "required": ["stop_agent"],
                    "properties": {
                      "stop_agent": {
                        "const": "true"
                      }
                    }
                  }
                ]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Message accepted.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": true
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        }
      }
    },
    "/chat/{chatId}/share": {
      "post": {
        "operationId": "shareChat",
        "summary": "Create a chat share link",
        "description": "Generates a public, read-only share URL for the chat.",
        "tags": ["Chat"],
        "security": [
          {
            "BearerAuth": ["chat:write"]
          }
        ],
        "parameters": [
          {
            "name": "chatId",
            "in": "path",
            "required": true,
            "description": "Chat id.",
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Share URL.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "url": {
                      "type": "string"
                    }
                  },
                  "required": ["url"]
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        }
      }
    },
    "/pr-reviews": {
      "get": {
        "operationId": "listPrReviews",
        "description": "Lists PR reviews for the organization. Results include only repositories within the token RBAC scopes.",
        "summary": "List PR reviews",
        "tags": ["PR Reviews"],
        "security": [
          {
            "BearerAuth": ["pr_reviews:read"]
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/Page"
          },
          {
            "$ref": "#/components/parameters/Limit"
          },
          {
            "name": "search",
            "in": "query",
            "required": false,
            "description": "Match repository, PR title, or PR number.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "status",
            "in": "query",
            "required": false,
            "description": "Comma-separated review statuses. Use pending, running, completed, posting, posted, or failed.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "group",
            "in": "query",
            "required": false,
            "description": "Filter by disposition group. `open` = the PR is still open with nothing demanding action (includes runs currently in flight). `attention` = failed runs, plus open PRs with open findings. `merged_open` = the PR merged while it still has open findings (run a re-review to verify them against the base branch). `passed` = merged/closed with nothing open. Deprecated names keep their original semantics: `active`/`running` = runs in flight, `completed` = terminal with nothing unresolved.",
            "schema": {
              "type": "string",
              "enum": [
                "open",
                "attention",
                "merged_open",
                "passed",
                "active",
                "running",
                "completed"
              ]
            }
          },
          {
            "name": "pr_state",
            "in": "query",
            "required": false,
            "description": "Filter by the pull request's own lifecycle. `open` also matches reviews whose PR state is unknown (older rows).",
            "schema": {
              "type": "string",
              "enum": ["open", "merged", "closed"]
            }
          },
          {
            "name": "repository_full_name",
            "in": "query",
            "required": false,
            "description": "Filter by repository (owner/name).",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "date_from",
            "in": "query",
            "required": false,
            "description": "ISO date lower bound (created_at).",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "date_to",
            "in": "query",
            "required": false,
            "description": "ISO date upper bound (created_at).",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "sort_by",
            "in": "query",
            "required": false,
            "description": "Sort by created_at or updated_at.",
            "schema": {
              "type": "string",
              "enum": ["created_at", "updated_at"],
              "default": "created_at"
            }
          },
          {
            "$ref": "#/components/parameters/SortOrder"
          },
          {
            "name": "include_counts",
            "in": "query",
            "required": false,
            "description": "Include exact counts for all review groups and lanes.",
            "schema": {
              "type": "boolean",
              "default": false
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Paginated PR reviews.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PaginatedResponse_PrReview"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        }
      }
    },
    "/pr-reviews/findings": {
      "get": {
        "operationId": "listPrReviewFindings",
        "description": "Lists every security issue that the organization's PR reviews caught. Each issue appears once. Repeated reports of the same issue across review runs of one pull request are collapsed. Dependency CVEs and retest rows are excluded. Results include only repositories within the token RBAC scopes.",
        "summary": "List security issues caught by PR reviews",
        "tags": ["PR Reviews"],
        "security": [
          {
            "BearerAuth": ["pr_reviews:read"]
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/Page"
          },
          {
            "description": "Maximum number of items per page. The default is 25 and the maximum is 100.",
            "name": "limit",
            "in": "query",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 100,
              "default": 25
            }
          },
          {
            "name": "severity",
            "in": "query",
            "required": false,
            "description": "Filter by severity.",
            "schema": {
              "$ref": "#/components/schemas/VulnerabilitySeverity"
            }
          },
          {
            "name": "pr_state",
            "in": "query",
            "required": false,
            "description": "Filter by the pull request lifecycle. Rows without a recorded state count as open.",
            "schema": {
              "type": "string",
              "enum": ["open", "merged", "closed"]
            }
          },
          {
            "name": "search",
            "in": "query",
            "required": false,
            "description": "Match issue title, CVE, repository, PR number, or PR title.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "repository_full_name",
            "in": "query",
            "required": false,
            "description": "Filter by repository (owner/name).",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "include_stats",
            "in": "query",
            "required": false,
            "description": "Set true to include all-time impact numbers in the response.",
            "schema": {
              "type": "boolean",
              "default": false
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Paginated security issues, newest first.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PaginatedResponse_PrReviewCaughtFinding"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        }
      }
    },
    "/pr-reviews/start": {
      "post": {
        "operationId": "startPrReview",
        "summary": "Start a PR review",
        "description": "Triggers a security review of a specific pull request. The target repository must be within the token's rbac scopes.",
        "tags": ["PR Reviews"],
        "security": [
          {
            "BearerAuth": ["pr_reviews:write"]
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "provider": {
                    "description": "Source control provider that hosts the pull request.",
                    "type": "string",
                    "enum": ["github", "gitlab", "bitbucket"]
                  },
                  "installation_id": {
                    "description": "Provider installation ID (for example the GitHub App installation) that has access to the repository.",
                    "type": "integer"
                  },
                  "repository_full_name": {
                    "type": "string",
                    "description": "owner/name."
                  },
                  "pr_number": {
                    "description": "Number of the pull request to review.",
                    "type": "integer"
                  }
                },
                "required": [
                  "provider",
                  "installation_id",
                  "repository_full_name",
                  "pr_number"
                ]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Review started.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/StartPrReviewResponse"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/TierLimitError"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "$ref": "#/components/responses/Conflict"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        }
      }
    },
    "/pr-reviews/settings": {
      "get": {
        "operationId": "getPrReviewSettings",
        "summary": "Get PR review settings",
        "tags": ["PR Reviews"],
        "security": [
          {
            "BearerAuth": ["pr_reviews:read"]
          }
        ],
        "responses": {
          "200": {
            "description": "Current settings.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PrReviewSettings"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        }
      },
      "patch": {
        "operationId": "updatePrReviewSettings",
        "description": "Updates organization PR review settings. Personal tokens must belong to an organization admin (parity with the dashboard).",
        "summary": "Update PR review settings",
        "tags": ["PR Reviews"],
        "security": [
          {
            "BearerAuth": ["pr_reviews:write"]
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UpdatePrReviewSettingsRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Updated settings.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/UpdatePrReviewSettingsResponse"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        }
      }
    },
    "/pr-reviews/{prReviewId}": {
      "get": {
        "operationId": "getPrReview",
        "description": "Fetches a PR review with its findings. Results are limited to repositories within the token's rbac scopes.",
        "summary": "Get a PR review",
        "tags": ["PR Reviews"],
        "security": [
          {
            "BearerAuth": ["pr_reviews:read"]
          }
        ],
        "parameters": [
          {
            "name": "prReviewId",
            "in": "path",
            "required": true,
            "description": "PR review id.",
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "PR review details.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PrReviewDetail"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        }
      }
    },
    "/knowledge": {
      "get": {
        "operationId": "listKnowledgeDocuments",
        "summary": "List knowledge documents",
        "tags": ["Knowledge"],
        "security": [
          {
            "BearerAuth": ["knowledge:read"]
          }
        ],
        "parameters": [
          {
            "name": "source_type",
            "in": "query",
            "required": false,
            "description": "Filter by source type.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "search",
            "in": "query",
            "required": false,
            "description": "Full-text search.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "description": "Max documents (default 60).",
            "schema": {
              "type": "integer"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Knowledge documents.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "organization_id": {
                      "type": "string",
                      "format": "uuid"
                    },
                    "docs": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/KnowledgeDocument"
                      }
                    },
                    "total": {
                      "type": "integer"
                    }
                  },
                  "required": ["organization_id", "docs", "total"]
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        }
      },
      "post": {
        "operationId": "createKnowledgeDocument",
        "summary": "Create a knowledge document",
        "tags": ["Knowledge"],
        "security": [
          {
            "BearerAuth": ["knowledge:write"]
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreateKnowledgeDocumentRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Created document.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    },
                    "doc": {
                      "$ref": "#/components/schemas/KnowledgeDocument"
                    }
                  },
                  "required": ["success", "doc"]
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        },
        "description": "Manage organization knowledge. Organization-global knowledge writes are not available to asset-scoped tokens."
      }
    },
    "/knowledge/{documentId}": {
      "patch": {
        "operationId": "updateKnowledgeDocument",
        "summary": "Update a knowledge document",
        "tags": ["Knowledge"],
        "security": [
          {
            "BearerAuth": ["knowledge:write"]
          }
        ],
        "parameters": [
          {
            "name": "documentId",
            "in": "path",
            "required": true,
            "description": "Document identifier. The API returns this identifier in list and create responses.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UpdateKnowledgeDocumentRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Updated document.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": true
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        },
        "description": "Manage organization knowledge. Organization-global knowledge writes are not available to asset-scoped tokens."
      },
      "delete": {
        "operationId": "deleteKnowledgeDocument",
        "summary": "Delete a knowledge document",
        "tags": ["Knowledge"],
        "security": [
          {
            "BearerAuth": ["knowledge:write"]
          }
        ],
        "parameters": [
          {
            "name": "documentId",
            "in": "path",
            "required": true,
            "description": "Document identifier. The API returns this identifier in list and create responses.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Deleted.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SuccessResponse"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        },
        "description": "Manage organization knowledge. Organization-global knowledge writes are not available to asset-scoped tokens."
      }
    },
    "/knowledge/policies": {
      "get": {
        "operationId": "listKnowledgePolicies",
        "summary": "List knowledge policies",
        "tags": ["Knowledge"],
        "security": [
          {
            "BearerAuth": ["knowledge:read"]
          }
        ],
        "responses": {
          "200": {
            "description": "Policies.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "policies": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/KnowledgePolicy"
                      }
                    }
                  },
                  "additionalProperties": true
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        }
      },
      "post": {
        "operationId": "upsertKnowledgePolicy",
        "description": "Creates or updates an organization knowledge policy. Personal tokens must belong to an organization admin (parity with the dashboard). Organization-global knowledge writes are not available to asset-scoped tokens.",
        "summary": "Create or update a knowledge policy",
        "tags": ["Knowledge"],
        "security": [
          {
            "BearerAuth": ["knowledge:write"]
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UpsertKnowledgePolicyRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Saved policy.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": true
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        }
      }
    },
    "/knowledge/policies/{policyKey}": {
      "delete": {
        "operationId": "deleteKnowledgePolicy",
        "description": "Deletes an organization knowledge policy. Personal tokens must belong to an organization admin (parity with the dashboard). Organization-global knowledge writes are not available to asset-scoped tokens.",
        "summary": "Delete a knowledge policy",
        "tags": ["Knowledge"],
        "security": [
          {
            "BearerAuth": ["knowledge:write"]
          }
        ],
        "parameters": [
          {
            "name": "policyKey",
            "in": "path",
            "required": true,
            "description": "Policy key.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Deleted.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SuccessResponse"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        }
      }
    },
    "/knowledge/repos": {
      "get": {
        "operationId": "listKnowledgeRepos",
        "summary": "List repository knowledge profiles",
        "tags": ["Knowledge"],
        "security": [
          {
            "BearerAuth": ["knowledge:read"]
          }
        ],
        "responses": {
          "200": {
            "description": "Repository profiles.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": true
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        }
      }
    },
    "/knowledge/repos/{repo}/entries": {
      "get": {
        "operationId": "listKnowledgeRepoEntries",
        "summary": "List knowledge entries for a repository",
        "tags": ["Knowledge"],
        "security": [
          {
            "BearerAuth": ["knowledge:read"]
          }
        ],
        "parameters": [
          {
            "name": "repo",
            "in": "path",
            "required": true,
            "description": "Repository identifier (owner/name or id).",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Repository knowledge entries.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": true
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        }
      }
    },
    "/knowledge/repos/{repo}/profile": {
      "patch": {
        "operationId": "updateKnowledgeRepoProfile",
        "summary": "Update a repository knowledge profile",
        "tags": ["Knowledge"],
        "security": [
          {
            "BearerAuth": ["knowledge:write"]
          }
        ],
        "parameters": [
          {
            "name": "repo",
            "in": "path",
            "required": true,
            "description": "Repository identifier (owner/name or id).",
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "description": "Profile fields to change. Accepts `title`, `content`, `tags`, and `metadata`. Omitted fields keep their current values.",
                "type": "object",
                "additionalProperties": true
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Updated profile.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": true
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        },
        "description": "Update a repository knowledge profile. Asset-scoped tokens may update profiles only for repositories covered by their token scopes."
      }
    },
    "/integrations": {
      "get": {
        "operationId": "listIntegrations",
        "summary": "List integrations",
        "description": "Connected SCM installations, ticketing accounts, and OAuth availability.",
        "tags": ["Integrations"],
        "security": [
          {
            "BearerAuth": ["integrations:read"]
          }
        ],
        "responses": {
          "200": {
            "description": "Integrations payload.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/IntegrationsPayload"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        }
      }
    },
    "/integrations/cloud": {
      "get": {
        "operationId": "listCloudConnections",
        "summary": "List cloud connections",
        "description": "Returns the cloud connections available to scans in the organization.",
        "tags": ["Integrations"],
        "security": [
          {
            "BearerAuth": ["integrations:read"]
          }
        ],
        "responses": {
          "200": {
            "description": "Cloud connections for the organization.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "connections": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/CloudConnection"
                      }
                    }
                  },
                  "required": ["connections"]
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        }
      }
    },
    "/integrations/cloud/{id}/projects": {
      "post": {
        "operationId": "addCloudConnectionProject",
        "summary": "Add a cloud project connection",
        "description": "Adds a project under an existing cloud connection. The source connection must own a provider credential.",
        "tags": ["Integrations"],
        "security": [
          {
            "BearerAuth": ["integrations:write"]
          }
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "Source cloud connection id.",
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/AddCloudConnectionProjectRequest"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Project connection created.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "connection": {
                      "$ref": "#/components/schemas/CloudConnection"
                    }
                  },
                  "required": ["connection"]
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "$ref": "#/components/responses/Conflict"
          }
        }
      }
    },
    "/integrations/{provider}": {
      "delete": {
        "operationId": "disconnectIntegration",
        "description": "Disconnects the integration for the organization. `installation_id` is required for GitHub, GitLab, and Bitbucket, which may have multiple installations; omit it for organization-wide providers such as Slack. Personal tokens must belong to an organization admin (parity with the dashboard).",
        "summary": "Disconnect an integration",
        "tags": ["Integrations"],
        "security": [
          {
            "BearerAuth": ["integrations:write"]
          }
        ],
        "parameters": [
          {
            "name": "provider",
            "in": "path",
            "required": true,
            "description": "Integration provider (e.g. gitlab, bitbucket, github).",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "installation_id",
            "in": "query",
            "required": false,
            "description": "Integer installation id. Required when provider is github, gitlab, or bitbucket; unsupported for organization-wide providers.",
            "schema": {
              "type": "integer"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Disconnected.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SuccessResponse"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        }
      }
    },
    "/integrations/{provider}/connect": {
      "post": {
        "operationId": "rejectUnsupportedIntegrationConnect",
        "summary": "Reject an unsupported token-based integration provider",
        "description": "Authenticated JSON fallback for provider identifiers other than the dedicated GitLab and Bitbucket connect routes. Always returns 400 after scope and admin checks.",
        "tags": ["Integrations"],
        "security": [
          {
            "BearerAuth": ["integrations:write"]
          }
        ],
        "parameters": [
          {
            "description": "Provider identifier. GitLab and Bitbucket use their dedicated routes, every other value is rejected.",
            "name": "provider",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          }
        }
      }
    },
    "/integrations/{provider}/validate": {
      "post": {
        "operationId": "rejectUnsupportedIntegrationValidate",
        "summary": "Reject an unsupported token-validation provider",
        "description": "Authenticated JSON fallback for provider identifiers other than the dedicated GitLab and Bitbucket validation routes. Always returns 400 after scope and admin checks.",
        "tags": ["Integrations"],
        "security": [
          {
            "BearerAuth": ["integrations:write"]
          }
        ],
        "parameters": [
          {
            "description": "Provider identifier. GitLab and Bitbucket use their dedicated routes, every other value is rejected.",
            "name": "provider",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          }
        }
      }
    },
    "/integrations/gitlab/connect": {
      "post": {
        "operationId": "connectGitlab",
        "description": "Connects GitLab with a personal access token. Personal tokens must belong to an organization admin (parity with the dashboard).",
        "summary": "Connect gitlab with a token",
        "tags": ["Integrations"],
        "security": [
          {
            "BearerAuth": ["integrations:write"]
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ConnectScmRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Connected.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": true
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "422": {
            "$ref": "#/components/responses/ValidationError"
          },
          "502": {
            "$ref": "#/components/responses/BadGateway"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        }
      }
    },
    "/integrations/gitlab/validate": {
      "post": {
        "operationId": "validateGitlab",
        "summary": "Validate a gitlab token",
        "description": "Checks a personal access token without persisting it. Personal tokens must belong to an organization admin (parity with the dashboard).",
        "tags": ["Integrations"],
        "security": [
          {
            "BearerAuth": ["integrations:write"]
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ConnectScmRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Validation result.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ValidateScmResponse"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "422": {
            "$ref": "#/components/responses/ValidationError"
          },
          "502": {
            "$ref": "#/components/responses/BadGateway"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        }
      }
    },
    "/integrations/bitbucket/connect": {
      "post": {
        "operationId": "connectBitbucket",
        "description": "Connects Bitbucket with an API token. Personal tokens must belong to an organization admin (parity with the dashboard).",
        "summary": "Connect bitbucket with a token",
        "tags": ["Integrations"],
        "security": [
          {
            "BearerAuth": ["integrations:write"]
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ConnectScmRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Connected.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": true
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "422": {
            "$ref": "#/components/responses/ValidationError"
          },
          "502": {
            "$ref": "#/components/responses/BadGateway"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        }
      }
    },
    "/integrations/bitbucket/validate": {
      "post": {
        "operationId": "validateBitbucket",
        "summary": "Validate a bitbucket token",
        "description": "Checks a personal access token without persisting it. Personal tokens must belong to an organization admin (parity with the dashboard).",
        "tags": ["Integrations"],
        "security": [
          {
            "BearerAuth": ["integrations:write"]
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ConnectScmRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Validation result.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ValidateScmResponse"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "422": {
            "$ref": "#/components/responses/ValidationError"
          },
          "502": {
            "$ref": "#/components/responses/BadGateway"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        }
      }
    },
    "/uploads/request": {
      "post": {
        "operationId": "requestUpload",
        "summary": "Request a signed upload URL",
        "description": "Reserves an upload and returns a signed URL (and resumable endpoint for large files) to PUT the file bytes to. Files ending in .zip are always treated as repository source archives and cannot be downgraded to documentation by setting category.",
        "tags": ["Uploads"],
        "security": [
          {
            "BearerAuth": ["uploads:write"]
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UploadRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Signed upload target.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/UploadRequestResponse"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        }
      }
    },
    "/uploads/complete": {
      "post": {
        "operationId": "completeUpload",
        "summary": "Finalize an upload",
        "description": "Marks a pending upload complete after the bytes have been transferred. Before the transition, every .zip is validated as a bounded repository archive, including pending legacy rows labeled as documentation. Repeating completion for an already-completed upload is idempotent. Asset-scoped tokens may finalize only uploads created by their effective user; unscoped tokens retain organization-wide access.",
        "tags": ["Uploads"],
        "security": [
          {
            "BearerAuth": ["uploads:write"]
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UploadCompleteRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Finalized upload.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Upload"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "$ref": "#/components/responses/Conflict"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        }
      }
    },
    "/uploads/{uploadId}": {
      "delete": {
        "operationId": "deleteUpload",
        "summary": "Delete an upload",
        "tags": ["Uploads"],
        "security": [
          {
            "BearerAuth": ["uploads:write"]
          }
        ],
        "parameters": [
          {
            "name": "uploadId",
            "in": "path",
            "required": true,
            "description": "Upload id.",
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Deleted.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SuccessResponse"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "Upload is attached to a scan and cannot be deleted.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        },
        "description": "Delete an unreferenced upload. Asset-scoped tokens may delete only uploads created by their effective user; unscoped tokens retain organization-wide access. Inaccessible upload IDs return 404. Uploads already attached to any scan are immutable and return 409 without removing the storage object or soft-deleting the row."
      }
    },
    "/scans/{scanId}/retests": {
      "get": {
        "operationId": "listScanRetests",
        "summary": "List scan retests",
        "description": "Lists retest scans spawned from this scan.",
        "tags": ["Scans"],
        "security": [
          {
            "BearerAuth": ["scans:read"]
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/ScanId"
          }
        ],
        "responses": {
          "200": {
            "description": "Retest scans.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": true
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        }
      }
    },
    "/scans/{scanId}/retest-all": {
      "post": {
        "operationId": "retestAllScanFindings",
        "summary": "Retest all findings",
        "description": "Starts a retest covering all of the scan's findings.",
        "tags": ["Scans"],
        "security": [
          {
            "BearerAuth": ["scans:write"]
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/ScanId"
          }
        ],
        "requestBody": {
          "required": false,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "scope": {
                    "type": "string",
                    "enum": ["all", "open"],
                    "description": "Choose whether to retest all findings or only open findings."
                  },
                  "upload_ids": {
                    "type": "array",
                    "minItems": 1,
                    "maxItems": 20,
                    "items": {
                      "type": "string",
                      "minLength": 1
                    },
                    "description": "Optional upload IDs that replace the repository uploads of the source scan for this retest."
                  }
                },
                "additionalProperties": false
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Retest started.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": true
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/TierLimitError"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        }
      }
    },
    "/scans/{scanId}/template": {
      "get": {
        "operationId": "getScanTemplate",
        "summary": "Get a scan as a reusable template",
        "description": "Returns the scan's configuration shaped for starting a new, similar scan. Credentials are returned as metadata only (username, notes, MFA method, has_stored_secret) — raw secrets such as passwords, TOTP seeds, MFA inboxes, and login URLs are never included. Use test_user_ids with POST /scans to reuse saved test users. Their secrets are rehydrated server-side.",
        "tags": ["Scans"],
        "security": [
          {
            "BearerAuth": ["scans:read"]
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/ScanId"
          }
        ],
        "responses": {
          "200": {
            "description": "Scan template.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": true
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        }
      }
    },
    "/scans/{scanId}/agents": {
      "get": {
        "operationId": "listScanAgents",
        "summary": "List the agents of a scan",
        "description": "Lists the agents that ran in this scan, with the task, status, parent agent, and finding count of each agent. Use the returned agent id with GET /scans/{scanId}/trace to read what one agent did.",
        "tags": ["Scans"],
        "security": [
          {
            "BearerAuth": ["scans:read"]
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/ScanId"
          }
        ],
        "responses": {
          "200": {
            "description": "Agents of the scan run.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": true
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        }
      }
    },
    "/scans/{scanId}/trace": {
      "get": {
        "operationId": "getScanAgentTrace",
        "summary": "Read one agent's trace",
        "description": "Returns one page of an agent's steps, oldest first. A step is an agent message, a tool call, a tool result, or a reported finding. Long payloads are shortened and marked with truncated. To read a shortened payload in full, call GET /scans/{scanId}/trace/{eventId} with the step's event_id. To read the next page, send the returned cursor value. If the response contains a note field, the trace is incomplete and the note tells you why.",
        "tags": ["Scans"],
        "security": [
          {
            "BearerAuth": ["scans:read"]
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/ScanId"
          },
          {
            "name": "agent_id",
            "in": "query",
            "required": true,
            "description": "Agent to read, from GET /scans/{scanId}/agents.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "cursor",
            "in": "query",
            "required": false,
            "description": "Cursor returned by the previous page.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "description": "Maximum number of steps to return. The default is 40 and the maximum is 100.",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 100
            }
          },
          {
            "name": "tool_name",
            "in": "query",
            "required": false,
            "description": "Return only the steps of one tool.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "One page of agent steps.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": true
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        }
      }
    },
    "/scans/{scanId}/trace/{eventId}": {
      "get": {
        "operationId": "getScanTraceStep",
        "summary": "Read one trace step in full",
        "description": "Returns the complete payload of one trace step. Use this endpoint when the trace returned the step with truncated set to true.",
        "tags": ["Scans"],
        "security": [
          {
            "BearerAuth": ["scans:read"]
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/ScanId"
          },
          {
            "name": "eventId",
            "in": "path",
            "required": true,
            "description": "The step's event_id, from the trace response.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "The step's complete payload.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": true
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        }
      }
    },
    "/vulnerabilities/{vulnerabilityId}/retest": {
      "post": {
        "operationId": "retestVulnerability",
        "summary": "Retest a vulnerability",
        "description": "Starts a focused retest to confirm whether a single finding is still exploitable.",
        "tags": ["Vulnerabilities"],
        "security": [
          {
            "BearerAuth": ["scans:write"]
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/VulnerabilityId"
          }
        ],
        "requestBody": {
          "required": false,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "upload_ids": {
                    "type": "array",
                    "minItems": 1,
                    "maxItems": 20,
                    "items": {
                      "type": "string",
                      "minLength": 1
                    },
                    "description": "Optional upload IDs that replace the repository uploads of the source scan for this retest."
                  }
                },
                "additionalProperties": false
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Retest started.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": true
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/TierLimitError"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        }
      }
    },
    "/vulnerabilities/{vulnerabilityId}/create-fix-pr": {
      "post": {
        "operationId": "createVulnerabilityFixPr",
        "summary": "Create a fix pull request",
        "description": "Opens a pull request with an agent-authored fix for the vulnerability. For code findings, this patches the affected files. For dependency findings (npm-based projects), it bumps the direct dependency in package.json or pins the vulnerable transitive package through the project's override mechanism (npm overrides, yarn resolutions, or pnpm overrides).",
        "tags": ["Vulnerabilities"],
        "security": [
          {
            "BearerAuth": ["vulnerabilities:write"]
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/VulnerabilityId"
          }
        ],
        "responses": {
          "200": {
            "description": "Fix PR created.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": true
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/TierLimitError"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        }
      }
    },
    "/vulnerabilities/{vulnerabilityId}/push": {
      "post": {
        "operationId": "pushVulnerabilityToTicket",
        "summary": "Export a vulnerability to a ticketing provider",
        "description": "Creates or syncs a Jira or Linear ticket for the vulnerability using the organization's connected ticketing integration. If a ticket already exists for the vulnerability and provider, its status is synced instead of creating a duplicate.",
        "tags": ["Vulnerabilities"],
        "security": [
          {
            "BearerAuth": ["integrations:write"]
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/VulnerabilityId"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": ["provider"],
                "properties": {
                  "provider": {
                    "type": "string",
                    "enum": ["jira", "linear"],
                    "description": "Connected ticketing provider to export to."
                  },
                  "collection_id": {
                    "type": ["string", "null"],
                    "description": "Optional destination collection (Jira project / Linear team or project) id. Defaults to the integration's configured destination."
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Ticket created or synced.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": true
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/TierLimitError"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "$ref": "#/components/responses/Conflict"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          },
          "502": {
            "$ref": "#/components/responses/BadGateway"
          }
        }
      }
    },
    "/vulnerabilities/bulk-push": {
      "post": {
        "operationId": "bulkPushVulnerabilitiesToTicket",
        "summary": "Export multiple vulnerabilities to a ticketing provider",
        "description": "Creates or syncs Jira or Linear tickets for up to 100 vulnerabilities in a single request. Each vulnerability is processed independently. The response reports per-vulnerability success or failure.",
        "tags": ["Vulnerabilities"],
        "security": [
          {
            "BearerAuth": ["integrations:write"]
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": ["provider", "vulnerability_ids"],
                "properties": {
                  "provider": {
                    "type": "string",
                    "enum": ["jira", "linear"],
                    "description": "Connected ticketing provider to export to."
                  },
                  "vulnerability_ids": {
                    "type": "array",
                    "items": {
                      "type": "string"
                    },
                    "maxItems": 100,
                    "description": "Vulnerability ids to export (deduplicated, max 100)."
                  },
                  "collection_id": {
                    "type": ["string", "null"],
                    "description": "Optional destination collection (Jira project / Linear team or project) id. Defaults to the integration's configured destination."
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Per-vulnerability export results.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": true
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/TierLimitError"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        }
      }
    },
    "/vulnerabilities/{vulnerabilityId}/history": {
      "get": {
        "operationId": "getVulnerabilityHistory",
        "summary": "Get vulnerability history",
        "description": "Returns lifecycle audit entries for one vulnerability, including status, severity, snooze, note, and reason changes.",
        "tags": ["Vulnerabilities"],
        "security": [
          {
            "BearerAuth": ["vulnerabilities:read"]
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/VulnerabilityId"
          }
        ],
        "responses": {
          "200": {
            "description": "Vulnerability history.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/VulnerabilityHistoryEntry"
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        }
      }
    },
    "/domains/{domainId}/test-users": {
      "get": {
        "operationId": "listTestUsers",
        "summary": "List domain test users",
        "tags": ["Test Users"],
        "security": [
          {
            "BearerAuth": ["test_users:read"]
          }
        ],
        "parameters": [
          {
            "name": "domainId",
            "in": "path",
            "required": true,
            "description": "Domain id.",
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Test users.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TestUserListResponse"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        }
      },
      "post": {
        "operationId": "createTestUser",
        "summary": "Create a domain test user",
        "description": "Creates a test account the agent can log in as. Secrets are encrypted at rest and never returned. Email-based MFA requires a Strix-managed inbox (see provision-inbox).",
        "tags": ["Test Users"],
        "security": [
          {
            "BearerAuth": ["test_users:write"]
          }
        ],
        "parameters": [
          {
            "name": "domainId",
            "in": "path",
            "required": true,
            "description": "Domain id.",
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreateTestUserRequest"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Test user created.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TestUser"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "422": {
            "$ref": "#/components/responses/ValidationError"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        }
      }
    },
    "/domains/{domainId}/test-users/{userId}": {
      "patch": {
        "operationId": "updateTestUser",
        "summary": "Update a domain test user",
        "tags": ["Test Users"],
        "security": [
          {
            "BearerAuth": ["test_users:write"]
          }
        ],
        "parameters": [
          {
            "name": "domainId",
            "in": "path",
            "required": true,
            "description": "Domain id.",
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          },
          {
            "name": "userId",
            "in": "path",
            "required": true,
            "description": "Test user id.",
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UpdateTestUserRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Updated test user.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TestUser"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "422": {
            "$ref": "#/components/responses/ValidationError"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        }
      },
      "delete": {
        "operationId": "deleteTestUser",
        "summary": "Delete a domain test user",
        "tags": ["Test Users"],
        "security": [
          {
            "BearerAuth": ["test_users:write"]
          }
        ],
        "parameters": [
          {
            "name": "domainId",
            "in": "path",
            "required": true,
            "description": "Domain id.",
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          },
          {
            "name": "userId",
            "in": "path",
            "required": true,
            "description": "Test user id.",
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Deleted (or detached from this domain).",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    },
                    "detached": {
                      "type": "boolean",
                      "description": "Present and true when the domain was detached from the user's scope instead of deleting the user."
                    }
                  },
                  "required": ["success"]
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "Org-wide test user cannot be deleted from a non-home domain.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        },
        "description": "Deletes the test user when called on its home domain. When called on another domain covered by the user's scope, only detaches that domain from the scope (response includes `detached: true`). Org-wide (all-domains) users can only be deleted from their home domain (409 otherwise)."
      }
    },
    "/domains/{domainId}/test-users/provision-inbox": {
      "post": {
        "operationId": "provisionTestUserInbox",
        "summary": "Provision a Strix-managed inbox",
        "description": "Creates a Strix-controlled AgentMail inbox (in the caller's org pod) for email-OTP / magic-link MFA. The agent reads verification emails from this inbox during scans.",
        "tags": ["Test Users"],
        "security": [
          {
            "BearerAuth": ["test_users:write"]
          }
        ],
        "parameters": [
          {
            "name": "domainId",
            "in": "path",
            "required": true,
            "description": "Domain id.",
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "requestBody": {
          "required": false,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ProvisionInboxRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Inbox provisioned.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": true
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "502": {
            "$ref": "#/components/responses/InternalError"
          },
          "503": {
            "$ref": "#/components/responses/InternalError"
          }
        }
      }
    },
    "/domains/{domainId}/test-users/{userId}/inbox": {
      "get": {
        "operationId": "readTestUserInbox",
        "summary": "Read a test user's inbox",
        "description": "Lists recent messages in the test user's Strix-managed inbox (e.g. OTP / magic-link emails).",
        "tags": ["Test Users"],
        "security": [
          {
            "BearerAuth": ["test_users:read"]
          }
        ],
        "parameters": [
          {
            "name": "domainId",
            "in": "path",
            "required": true,
            "description": "Domain id.",
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          },
          {
            "name": "userId",
            "in": "path",
            "required": true,
            "description": "Test user id.",
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "description": "Max messages (default 25).",
            "schema": {
              "type": "integer"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Inbox messages.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/InboxMessageList"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "502": {
            "$ref": "#/components/responses/InternalError"
          },
          "503": {
            "$ref": "#/components/responses/InternalError"
          }
        }
      }
    },
    "/domains/{domainId}/test-users/{userId}/inbox/{messageId}": {
      "get": {
        "operationId": "readTestUserInboxMessage",
        "summary": "Read a single inbox message",
        "description": "Returns the full message body as readable text (HTML converted to text so OTP codes and magic-link URLs are preserved).",
        "tags": ["Test Users"],
        "security": [
          {
            "BearerAuth": ["test_users:read"]
          }
        ],
        "parameters": [
          {
            "name": "domainId",
            "in": "path",
            "required": true,
            "description": "Domain id.",
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          },
          {
            "name": "userId",
            "in": "path",
            "required": true,
            "description": "Test user id.",
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          },
          {
            "name": "messageId",
            "in": "path",
            "required": true,
            "description": "Inbox message id.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Inbox message.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/InboxMessage"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "502": {
            "$ref": "#/components/responses/InternalError"
          },
          "503": {
            "$ref": "#/components/responses/InternalError"
          }
        }
      }
    },
    "/domains/{domainId}/test-users/{userId}/verify": {
      "post": {
        "operationId": "verifyTestUserLogin",
        "summary": "Verify a test user's login",
        "description": "Starts a short agent run (usually a minute or two) that drives the target's real login form with the saved credentials and reports a structured outcome, so a broken login surfaces before a scan. Returns 202 with a pending verification, or 200 with an in-flight / recent one that is reused. The domain must be ownership-verified. The login URL may live on another host (SSO tenant, IdP, separate auth site) as long as it is a public http(s) endpoint.",
        "tags": ["Test Users"],
        "security": [
          {
            "BearerAuth": ["test_users:write"]
          }
        ],
        "parameters": [
          {
            "name": "domainId",
            "in": "path",
            "required": true,
            "description": "Domain id.",
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          },
          {
            "name": "userId",
            "in": "path",
            "required": true,
            "description": "Test user id.",
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          },
          {
            "name": "force",
            "in": "query",
            "required": false,
            "description": "Set to `1` to re-verify even when a recent result exists (use after changing the credentials).",
            "schema": {
              "type": "string",
              "enum": ["1"]
            }
          }
        ],
        "responses": {
          "200": {
            "description": "An in-flight or recent verification was reused.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TestUserAuthCheck"
                }
              }
            }
          },
          "202": {
            "description": "Verification started.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TestUserAuthCheck"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "422": {
            "$ref": "#/components/responses/ValidationError"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        }
      },
      "get": {
        "operationId": "getTestUserLoginVerification",
        "summary": "Get the latest login verification",
        "description": "Returns the latest login verification for a saved test user, or `null` if it has never been verified. Poll this while a verification is `pending` / `running`.",
        "tags": ["Test Users"],
        "security": [
          {
            "BearerAuth": ["test_users:read"]
          }
        ],
        "parameters": [
          {
            "name": "domainId",
            "in": "path",
            "required": true,
            "description": "Domain id.",
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          },
          {
            "name": "userId",
            "in": "path",
            "required": true,
            "description": "Test user id.",
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Latest login verification. If the test user has no verification, the value is `null`.",
            "content": {
              "application/json": {
                "schema": {
                  "oneOf": [
                    {
                      "$ref": "#/components/schemas/TestUserAuthCheck"
                    },
                    {
                      "type": "null"
                    }
                  ]
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        }
      }
    },
    "/license": {
      "get": {
        "operationId": "getLicenseStatus",
        "summary": "Get license status",
        "description": "License state for self-hosted installs: whether licensing is enforced, the current state (unlicensed/valid/expired/grace_exceeded/invalid), signed entitlements (seat, domain, repo, developer, pentest, and concurrency limits plus feature flags), expiry, and install-wide aggregate usage counts. Licenses are verified offline from a signed token, so there is no sync (last_synced_at is always null). On SaaS this always reports enforced=false. Requires the license:read scope. Personal tokens must belong to an org admin (service tokens are admin-issued and exempt).",
        "tags": ["License"],
        "security": [
          {
            "BearerAuth": ["license:read"]
          }
        ],
        "responses": {
          "200": {
            "description": "License status",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "enforced": {
                      "type": "boolean"
                    },
                    "state": {
                      "type": "string",
                      "enum": [
                        "unlicensed",
                        "valid",
                        "expired",
                        "grace_exceeded",
                        "invalid"
                      ]
                    },
                    "customer_name": {
                      "type": ["string", "null"]
                    },
                    "license_type": {
                      "type": ["string", "null"]
                    },
                    "expires_at": {
                      "type": ["string", "null"],
                      "description": "ISO date. A null value means the license never expires"
                    },
                    "last_synced_at": {
                      "type": ["string", "null"],
                      "description": "Always null: licenses are verified offline, nothing syncs"
                    },
                    "entitlements": {
                      "type": ["object", "null"],
                      "properties": {
                        "max_dashboard_users": {
                          "type": "integer",
                          "description": "0 = unlimited"
                        },
                        "max_domains": {
                          "type": "integer"
                        },
                        "max_repos": {
                          "type": "integer"
                        },
                        "max_developers": {
                          "type": "integer"
                        },
                        "max_pentests_per_month": {
                          "type": "integer"
                        },
                        "max_concurrent_scans": {
                          "type": "integer"
                        },
                        "pr_reviews_enabled": {
                          "type": "boolean"
                        },
                        "on_demand_pentests_enabled": {
                          "type": "boolean"
                        },
                        "chat_enabled": {
                          "type": "boolean"
                        }
                      }
                    },
                    "usage": {
                      "type": ["object", "null"],
                      "properties": {
                        "domains": {
                          "type": "integer"
                        },
                        "repositories": {
                          "type": "integer"
                        },
                        "pentests_this_month": {
                          "type": "integer"
                        },
                        "running_scans": {
                          "type": "integer"
                        },
                        "active_developers_this_month": {
                          "type": "integer"
                        },
                        "pr_reviews_this_month": {
                          "type": "integer"
                        },
                        "chats_this_month": {
                          "type": "integer"
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          }
        }
      }
    },
    "/supply-chain/summary": {
      "get": {
        "operationId": "getSupplyChainOrgSummary",
        "summary": "Get organization supply-chain summary",
        "tags": ["Supply Chain"],
        "security": [
          {
            "BearerAuth": ["supply_chain:read"]
          }
        ],
        "responses": {
          "200": {
            "description": "Org-wide supply-chain totals and per-repository summaries.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SupplyChainOrgSummary"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        }
      }
    },
    "/repositories/{repositoryId}/supply-chain/summary": {
      "get": {
        "operationId": "getRepositorySupplyChainSummary",
        "summary": "Get repository supply-chain summary",
        "description": "Counts for the resolved scope. Pull-request and merge-request scans keep no SBOM snapshot, so scoping to one of those jobs with `job_id` serves `component_count`, `finding_count`, `malicious_count`, `suspicious_count`, `vulnerable_count`, and `severity_counts` from the job's stored scan result. For those scopes `latest_snapshot` is null and `ecosystem_counts` is empty, because neither can be derived without stored component rows. A change-scan job that ran before scan results were stored reports zero counts.",
        "tags": ["Supply Chain"],
        "security": [
          {
            "BearerAuth": ["supply_chain:read"]
          }
        ],
        "parameters": [
          {
            "description": "UUID of the repository. Use the `id` field of a repository from `listRepositories`.",
            "name": "repositoryId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          },
          {
            "name": "job_id",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Scope the view to a specific supply-chain job."
          },
          {
            "name": "snapshot_id",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Scope the view to a specific SBOM snapshot."
          }
        ],
        "responses": {
          "200": {
            "description": "Repository supply-chain summary for the resolved scope.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        }
      }
    },
    "/repositories/{repositoryId}/supply-chain/components": {
      "get": {
        "operationId": "listRepositorySupplyChainComponents",
        "summary": "List repository SBOM components",
        "tags": ["Supply Chain"],
        "security": [
          {
            "BearerAuth": ["supply_chain:read"]
          }
        ],
        "parameters": [
          {
            "description": "UUID of the repository. Use the `id` field of a repository from `listRepositories`.",
            "name": "repositoryId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          },
          {
            "name": "job_id",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Scope the view to a specific supply-chain job."
          },
          {
            "name": "snapshot_id",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Scope the view to a specific SBOM snapshot."
          },
          {
            "name": "component_id",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Return only the given component."
          },
          {
            "name": "ecosystem",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Filter by package ecosystem."
          },
          {
            "name": "status",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Filter by component status."
          },
          {
            "name": "relationship",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Filter by dependency relationship (direct/transitive)."
          },
          {
            "name": "source_file",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Filter by manifest/lockfile source path."
          },
          {
            "name": "q",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Free-text search over component names."
          },
          {
            "name": "changed",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Only components changed in this snapshot (true/false)."
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer"
            },
            "description": "Page size (default 100)."
          },
          {
            "name": "offset",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer"
            },
            "description": "Page offset (default 0)."
          }
        ],
        "responses": {
          "200": {
            "description": "Snapshot metadata, a page of components, and paging meta.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        }
      }
    },
    "/repositories/{repositoryId}/supply-chain/findings": {
      "get": {
        "operationId": "listRepositorySupplyChainFindings",
        "summary": "List repository supply-chain findings",
        "description": "Open findings for the resolved scope. Pull-request and merge-request scans keep no SBOM snapshot, so scoping to one of those jobs with `job_id` serves the findings from the job's stored scan result: `snapshot` is null, and on each finding `id`, `source`, `first_seen_at`, and `last_seen_at` are null because no stored finding row exists to carry them. For those scopes `component_id` matches nothing (there are no stored component rows to filter on), and the list is capped at the first 100 findings while `finding_count` on the summary endpoint still covers the whole set. A change-scan job that ran before scan results were stored returns an empty list.",
        "tags": ["Supply Chain"],
        "security": [
          {
            "BearerAuth": ["supply_chain:read"]
          }
        ],
        "parameters": [
          {
            "description": "UUID of the repository. Use the `id` field of a repository from `listRepositories`.",
            "name": "repositoryId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          },
          {
            "name": "job_id",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Scope the view to a specific supply-chain job."
          },
          {
            "name": "snapshot_id",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Scope the view to a specific SBOM snapshot."
          },
          {
            "name": "component_id",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Return findings for the given component only."
          }
        ],
        "responses": {
          "200": {
            "description": "Snapshot metadata and supply-chain findings for the resolved scope.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        }
      }
    },
    "/repositories/{repositoryId}/supply-chain/sbom": {
      "get": {
        "operationId": "exportRepositorySbom",
        "summary": "Export repository SBOM",
        "tags": ["Supply Chain"],
        "security": [
          {
            "BearerAuth": ["supply_chain:read"]
          }
        ],
        "parameters": [
          {
            "description": "UUID of the repository. Use the `id` field of a repository from `listRepositories`.",
            "name": "repositoryId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          },
          {
            "name": "job_id",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Scope the view to a specific supply-chain job."
          },
          {
            "name": "snapshot_id",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Scope the view to a specific SBOM snapshot."
          },
          {
            "name": "format",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "enum": ["spdx", "cyclonedx"],
              "default": "spdx"
            },
            "description": "SBOM export format."
          }
        ],
        "responses": {
          "200": {
            "description": "SBOM document as a JSON attachment.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        }
      }
    },
    "/repositories/{repositoryId}/supply-chain/scan": {
      "post": {
        "operationId": "startRepositorySupplyChainScan",
        "summary": "Trigger a supply-chain scan",
        "tags": ["Supply Chain"],
        "security": [
          {
            "BearerAuth": ["supply_chain:write"]
          }
        ],
        "parameters": [
          {
            "description": "UUID of the repository. Use the `id` field of a repository from `listRepositories`.",
            "name": "repositoryId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Scan enqueued (or skipped with a reason).",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        }
      }
    },
    "/repositories/{repositoryId}/supply-chain/policy": {
      "patch": {
        "operationId": "updateRepositorySupplyChainPolicy",
        "summary": "Update repository supply-chain policy",
        "tags": ["Supply Chain"],
        "security": [
          {
            "BearerAuth": ["supply_chain:write"]
          }
        ],
        "parameters": [
          {
            "description": "UUID of the repository. Use the `id` field of a repository from `listRepositories`.",
            "name": "repositoryId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "supply_chain_enabled": {
                    "description": "When true, Strix scans the dependencies of this repository.",
                    "type": "boolean"
                  },
                  "supply_chain_pr_checks_enabled": {
                    "description": "When true, Strix checks dependency changes on pull requests.",
                    "type": "boolean"
                  },
                  "supply_chain_policy_mode": {
                    "description": "What happens when a pull request adds a risky dependency. `monitor` only records it, `comment` posts a review comment, `block` fails the check.",
                    "type": "string",
                    "enum": ["monitor", "comment", "block"]
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Updated repository supply-chain policy fields.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        }
      }
    },
    "/chat/{chatId}/files": {
      "get": {
        "operationId": "listChatWorkspaceFiles",
        "summary": "List exportable files in a chat's workspace",
        "description": "Lists files in the running chat agent's /workspace so artifacts (reports, PoCs, generated files) can be exported. The sandbox response is limited to 2 MiB and 10,000 entries before JSON normalization.",
        "tags": ["Chat"],
        "security": [
          {
            "BearerAuth": ["chat:read"]
          }
        ],
        "parameters": [
          {
            "name": "chatId",
            "in": "path",
            "required": true,
            "description": "Chat id.",
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Workspace files.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "files": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "path": {
                            "type": "string"
                          },
                          "size": {
                            "type": "integer"
                          }
                        },
                        "required": ["path", "size"]
                      }
                    }
                  },
                  "required": ["files"]
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "413": {
            "description": "Workspace listing exceeds 2 MiB or 10,000 entries."
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          },
          "502": {
            "description": "Chat sandbox unreachable or returned an invalid workspace listing."
          },
          "503": {
            "description": "Chat sandbox not ready."
          }
        }
      }
    },
    "/chat/{chatId}/files/archive": {
      "get": {
        "operationId": "downloadChatWorkspaceArchive",
        "summary": "Download a chat's whole workspace as a zip",
        "description": "Streams every file in the running chat agent's /workspace as a zip archive using safe relative POSIX entry names. Production follows response backpressure and aborts in-flight sandbox downloads if the consumer disconnects, so the whole archive is never buffered. Export is rejected before streaming when the workspace listing exceeds 2 MiB or 10,000 entries, any file is over 50 MiB, or advertised content exceeds 512 MiB total. Each file response is bounded before JSON parsing and base64 decoding, and the stream fails instead of returning a partial archive if a file grows beyond 50 MiB after listing, actual total content exceeds 512 MiB, a file cannot be read, or the 30-second archive deadline expires.",
        "tags": ["Chat"],
        "security": [
          {
            "BearerAuth": ["chat:read"]
          }
        ],
        "parameters": [
          {
            "name": "chatId",
            "in": "path",
            "required": true,
            "description": "Chat id.",
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Zip archive of the workspace.",
            "content": {
              "application/zip": {
                "schema": {
                  "type": "string",
                  "format": "binary"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "413": {
            "description": "Workspace exceeds the 2 MiB/10,000-entry listing, 50 MiB per-file, or 512 MiB total archive limit."
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          },
          "502": {
            "description": "Chat sandbox unreachable or returned invalid workspace export data."
          },
          "503": {
            "description": "Chat sandbox not ready."
          }
        }
      }
    },
    "/chat/{chatId}/files/download": {
      "get": {
        "operationId": "downloadChatWorkspaceFile",
        "summary": "Download a file from a chat's workspace",
        "description": "Downloads one file (max 50 MiB) from the running chat agent's /workspace. The bridge response is bounded before JSON parsing and base64 decoding.",
        "tags": ["Chat"],
        "security": [
          {
            "BearerAuth": ["chat:read"]
          }
        ],
        "parameters": [
          {
            "name": "chatId",
            "in": "path",
            "required": true,
            "description": "Chat id.",
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          },
          {
            "name": "path",
            "in": "query",
            "required": true,
            "description": "Absolute file path under /workspace.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "File contents.",
            "content": {
              "application/octet-stream": {
                "schema": {
                  "type": "string",
                  "format": "binary"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "413": {
            "description": "File too large to export."
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          },
          "502": {
            "description": "Chat sandbox unreachable or returned invalid workspace file data."
          },
          "503": {
            "description": "Chat sandbox not ready."
          }
        }
      }
    },
    "/chat/{chatId}/terminal": {
      "post": {
        "operationId": "execChatTerminalCommand",
        "summary": "Run a command in a chat's agent sandbox",
        "description": "Executes one non-interactive command inside the chat agent's sandbox, starting from a directory under /workspace. Execution time and output size are capped by the runtime, and every attempt is recorded as a chat.terminal.command audit event.",
        "tags": ["Chat"],
        "security": [
          {
            "BearerAuth": ["chat:write"]
          }
        ],
        "parameters": [
          {
            "name": "chatId",
            "in": "path",
            "required": true,
            "description": "Chat id.",
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "command": {
                    "type": "string",
                    "maxLength": 4096,
                    "description": "Command to run in the sandbox shell."
                  },
                  "cwd": {
                    "type": "string",
                    "default": "/workspace",
                    "description": "Working directory; must be /workspace or a path below it. Pass the `cwd` from the previous response to make `cd` carry over between commands."
                  }
                },
                "required": ["command"]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Command output.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "output": {
                      "type": "string"
                    },
                    "cwd": {
                      "type": "string",
                      "description": "Directory the shell ended in; send it as `cwd` on the next call to continue there."
                    },
                    "exit_code": {
                      "type": ["integer", "null"]
                    },
                    "truncated": {
                      "type": "boolean"
                    }
                  },
                  "required": ["output", "cwd", "truncated"]
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "413": {
            "description": "Command too long."
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          },
          "502": {
            "description": "Chat sandbox unreachable."
          },
          "503": {
            "description": "Chat sandbox not ready."
          },
          "504": {
            "description": "Command exceeded the sandbox time limit."
          }
        }
      }
    },
    "/chat/{chatId}/credentials": {
      "get": {
        "operationId": "listChatCredentials",
        "summary": "List a chat's engagement credentials",
        "description": "Returns metadata for the credentials armed on a chat plus the saved domain test users the caller may attach. Secret material (passwords, TOTP seeds) is never returned.",
        "tags": ["Chat"],
        "security": [
          {
            "BearerAuth": ["chat:read"]
          }
        ],
        "parameters": [
          {
            "name": "chatId",
            "in": "path",
            "required": true,
            "description": "Chat id.",
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          },
          {
            "name": "scan_ids",
            "in": "query",
            "required": false,
            "description": "Comma-separated pentest ids whose stored logins should be offered for reuse; each is re-checked against the caller's access scope.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Credential metadata.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "credentials": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "label": {
                            "type": "string"
                          },
                          "username": {
                            "type": "string"
                          },
                          "login_url": {
                            "type": ["string", "null"]
                          },
                          "mfa_method": {
                            "type": "string",
                            "enum": ["none", "totp", "email_otp", "magic_link"]
                          },
                          "has_password": {
                            "type": "boolean"
                          },
                          "has_totp_secret": {
                            "type": "boolean"
                          },
                          "test_user_id": {
                            "type": ["string", "null"],
                            "description": "Set when the credential came from a saved domain test user."
                          }
                        },
                        "required": [
                          "label",
                          "username",
                          "mfa_method",
                          "has_password",
                          "has_totp_secret"
                        ]
                      }
                    },
                    "available_test_users": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "id": {
                            "type": "string",
                            "format": "uuid"
                          },
                          "label": {
                            "type": "string"
                          },
                          "username": {
                            "type": "string"
                          },
                          "domain": {
                            "type": "string"
                          },
                          "login_url": {
                            "type": ["string", "null"]
                          },
                          "mfa_method": {
                            "type": "string",
                            "enum": ["none", "totp", "email_otp", "magic_link"]
                          },
                          "has_password": {
                            "type": "boolean"
                          },
                          "has_totp_secret": {
                            "type": "boolean"
                          }
                        },
                        "required": [
                          "id",
                          "label",
                          "username",
                          "domain",
                          "mfa_method",
                          "has_password",
                          "has_totp_secret"
                        ]
                      }
                    },
                    "available_scan_credentials": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "scan_id": {
                            "type": "string",
                            "format": "uuid"
                          },
                          "scan_title": {
                            "type": "string"
                          },
                          "username": {
                            "type": "string"
                          },
                          "login_url": {
                            "type": ["string", "null"]
                          },
                          "mfa_method": {
                            "type": "string",
                            "enum": ["none", "totp", "email_otp", "magic_link"]
                          },
                          "has_password": {
                            "type": "boolean"
                          },
                          "has_totp_secret": {
                            "type": "boolean"
                          }
                        },
                        "required": [
                          "scan_id",
                          "scan_title",
                          "username",
                          "mfa_method",
                          "has_password",
                          "has_totp_secret"
                        ]
                      }
                    }
                  },
                  "required": [
                    "credentials",
                    "available_test_users",
                    "available_scan_credentials"
                  ]
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        }
      },
      "post": {
        "operationId": "attachChatCredentials",
        "summary": "Arm a chat with engagement credentials",
        "description": "Attaches saved domain test users and/or credentials supplied in the request to a chat, so its agent can authenticate to the target. Values are encrypted at rest and handed only to the chat's trusted orchestrator, where host-side auth tools expose derived values (a resolved login, a TOTP code) to the agent; they never enter the chat transcript, the model context, or the agent sandbox. Re-attaching an account replaces it. Recorded as a chat.credentials.attached audit event.",
        "tags": ["Chat"],
        "security": [
          {
            "BearerAuth": ["chat:write"]
          }
        ],
        "parameters": [
          {
            "name": "chatId",
            "in": "path",
            "required": true,
            "description": "Chat id.",
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "test_user_ids": {
                    "type": "array",
                    "items": {
                      "type": "string",
                      "format": "uuid"
                    },
                    "description": "Saved domain test users to attach; each must sit on a domain within the caller's access scope."
                  },
                  "credentials": {
                    "type": "array",
                    "description": "Credentials supplied for this chat only (not saved to a domain).",
                    "items": {
                      "type": "object",
                      "properties": {
                        "label": {
                          "type": "string",
                          "description": "Display label; defaults to the username."
                        },
                        "username": {
                          "type": "string"
                        },
                        "password": {
                          "type": "string"
                        },
                        "login_url": {
                          "type": "string"
                        },
                        "notes": {
                          "type": "string"
                        },
                        "mfa_method": {
                          "type": "string",
                          "enum": ["none", "totp", "email_otp", "magic_link"]
                        },
                        "totp_secret": {
                          "type": "string",
                          "description": "Shared TOTP seed; used when mfa_method is totp."
                        },
                        "mfa_email": {
                          "type": "string",
                          "description": "Strix inbox that receives the email code or magic link."
                        }
                      },
                      "required": ["username"]
                    }
                  },
                  "scan_ids": {
                    "type": "array",
                    "items": {
                      "type": "string",
                      "format": "uuid"
                    },
                    "description": "Pentests whose stored credentials this chat should reuse; the caller must have access to each pentest's targets."
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Credentials armed.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "credentials": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "label": {
                            "type": "string"
                          },
                          "username": {
                            "type": "string"
                          },
                          "login_url": {
                            "type": ["string", "null"]
                          },
                          "mfa_method": {
                            "type": "string",
                            "enum": ["none", "totp", "email_otp", "magic_link"]
                          },
                          "has_password": {
                            "type": "boolean"
                          },
                          "has_totp_secret": {
                            "type": "boolean"
                          },
                          "test_user_id": {
                            "type": ["string", "null"],
                            "description": "Set when the credential came from a saved domain test user."
                          }
                        },
                        "required": [
                          "label",
                          "username",
                          "mfa_method",
                          "has_password",
                          "has_totp_secret"
                        ]
                      }
                    },
                    "delivered": {
                      "type": "boolean",
                      "description": "False when the chat was still booting; the credentials are stored and handed to its orchestrator at launch."
                    }
                  },
                  "required": ["credentials", "delivered"]
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "422": {
            "$ref": "#/components/responses/ValidationError"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        }
      },
      "delete": {
        "operationId": "revokeChatCredentials",
        "summary": "Revoke a chat's engagement credentials",
        "description": "Clears every credential armed on the chat, in storage and in the running orchestrator. Recorded as a chat.credentials.revoked audit event.",
        "tags": ["Chat"],
        "security": [
          {
            "BearerAuth": ["chat:write"]
          }
        ],
        "parameters": [
          {
            "name": "chatId",
            "in": "path",
            "required": true,
            "description": "Chat id.",
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Credentials revoked.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "revoked": {
                      "type": "integer"
                    }
                  },
                  "required": ["revoked"]
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        }
      }
    },
    "/chat/{chatId}/domains": {
      "put": {
        "operationId": "updateChatDomainScope",
        "summary": "Re-scope a chat to verified domains",
        "description": "Replaces the verified organization domains a chat is authorized against, including while it is running: the domains are re-validated (owned, verified, inside the caller's access scopes), persisted, and pushed to the running agent, which re-labels proxy traffic and is told its scope changed. An empty list restores organization-wide authorization.",
        "tags": ["Chat"],
        "security": [
          {
            "BearerAuth": ["chat:write"]
          }
        ],
        "parameters": [
          {
            "name": "chatId",
            "in": "path",
            "required": true,
            "description": "Chat id.",
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "domain_ids": {
                    "type": "array",
                    "items": {
                      "type": "string",
                      "format": "uuid"
                    },
                    "description": "Verified organization domain ids. Empty restores organization-wide authorization."
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The chat's new scope.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "scoped_domains": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "id": {
                            "type": "string"
                          },
                          "domain": {
                            "type": "string"
                          }
                        }
                      }
                    },
                    "delivered": {
                      "type": "boolean",
                      "description": "Whether the running sandbox acknowledged the new scope."
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "A domain is unknown, unverified or out of the caller's access scope."
          },
          "403": {
            "description": "Insufficient role or scope."
          },
          "404": {
            "description": "Chat not found."
          }
        }
      }
    },
    "/chat/{chatId}/findings": {
      "get": {
        "operationId": "listChatFindings",
        "summary": "List the findings an agent reported in a chat",
        "description": "Findings discovered inside a chat are exploratory and stay out of the organization's issue lists until a member files one; filed_at reflects that state.",
        "tags": ["Chat"],
        "security": [
          {
            "BearerAuth": ["chat:read"]
          }
        ],
        "parameters": [
          {
            "name": "chatId",
            "in": "path",
            "required": true,
            "description": "Chat id.",
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Chat findings.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "findings": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "id": {
                            "type": "string"
                          },
                          "title": {
                            "type": "string"
                          },
                          "severity": {
                            "type": "string"
                          },
                          "status": {
                            "type": "string"
                          },
                          "target": {
                            "type": ["string", "null"]
                          },
                          "endpoint": {
                            "type": ["string", "null"]
                          },
                          "method": {
                            "type": ["string", "null"]
                          },
                          "cvss": {
                            "type": ["number", "null"]
                          },
                          "created_at": {
                            "type": "string",
                            "format": "date-time"
                          },
                          "chat_id": {
                            "type": ["string", "null"],
                            "format": "uuid"
                          },
                          "filed_at": {
                            "type": ["string", "null"],
                            "format": "date-time",
                            "description": "Set once the finding has been filed into the organization's issue list."
                          },
                          "filed_by": {
                            "type": ["string", "null"],
                            "description": "Id of the member who filed it."
                          }
                        }
                      }
                    }
                  },
                  "required": ["findings"]
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        }
      }
    },
    "/chat/{chatId}/findings/{findingId}": {
      "get": {
        "operationId": "getChatFinding",
        "summary": "Get a finding reported in a chat",
        "description": "Returns the complete vulnerability row for a finding reported in the chat. The row includes findings that are not filed in the organization's issue list.",
        "tags": ["Chat"],
        "security": [
          {
            "BearerAuth": ["chat:read"]
          }
        ],
        "parameters": [
          {
            "name": "chatId",
            "in": "path",
            "required": true,
            "description": "Chat id.",
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          },
          {
            "name": "findingId",
            "in": "path",
            "required": true,
            "description": "Finding id.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Chat finding.",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/Vulnerability"
                    },
                    {
                      "type": "object",
                      "properties": {
                        "chat_id": {
                          "type": ["string", "null"],
                          "format": "uuid"
                        },
                        "filed_at": {
                          "type": ["string", "null"],
                          "format": "date-time",
                          "description": "Set after a member files the finding into the organization's issue list."
                        },
                        "filed_by": {
                          "type": ["string", "null"],
                          "description": "Identifies the member who filed the finding."
                        }
                      }
                    }
                  ]
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        }
      }
    },
    "/chat/{chatId}/findings/{findingId}/file": {
      "post": {
        "operationId": "fileChatFinding",
        "summary": "File a chat finding into the organization's issues",
        "description": "Adds a chat-discovered finding to the organization's issue list. Idempotent: re-filing returns the same finding. When the organization already tracks an equivalent finding (same title, target and endpoint), the finding is left unfiled and duplicate_of identifies the existing issue. Recorded as a chat.finding.filed audit event.",
        "tags": ["Chat"],
        "security": [
          {
            "BearerAuth": ["chat:write"]
          }
        ],
        "parameters": [
          {
            "name": "chatId",
            "in": "path",
            "required": true,
            "description": "Chat id.",
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          },
          {
            "name": "findingId",
            "in": "path",
            "required": true,
            "description": "Finding id.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Filed finding.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "finding": {
                      "type": "object",
                      "properties": {
                        "id": {
                          "type": "string"
                        },
                        "title": {
                          "type": "string"
                        },
                        "severity": {
                          "type": "string"
                        },
                        "status": {
                          "type": "string"
                        },
                        "target": {
                          "type": ["string", "null"]
                        },
                        "endpoint": {
                          "type": ["string", "null"]
                        },
                        "method": {
                          "type": ["string", "null"]
                        },
                        "cvss": {
                          "type": ["number", "null"]
                        },
                        "created_at": {
                          "type": "string",
                          "format": "date-time"
                        },
                        "chat_id": {
                          "type": ["string", "null"],
                          "format": "uuid"
                        },
                        "filed_at": {
                          "type": ["string", "null"],
                          "format": "date-time",
                          "description": "Set once the finding has been filed into the organization's issue list."
                        },
                        "filed_by": {
                          "type": ["string", "null"],
                          "description": "Id of the member who filed it."
                        }
                      }
                    },
                    "duplicate_of": {
                      "type": ["string", "null"],
                      "description": "Existing organization finding that already covers this one."
                    }
                  },
                  "required": ["finding"]
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        }
      }
    },
    "/settings/notifications": {
      "get": {
        "operationId": "getNotificationSettings",
        "summary": "Get notification settings",
        "description": "Returns the organization's notification settings, including SLA deadline reminder configuration.",
        "tags": ["Organization"],
        "security": [
          {
            "BearerAuth": ["organizations:read"]
          }
        ],
        "responses": {
          "200": {
            "description": "Notification settings.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/NotificationSettings"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        }
      },
      "patch": {
        "operationId": "updateNotificationSettings",
        "summary": "Update notification settings",
        "description": "Update the organization's notification settings (admin only). Enable SLA deadline reminders and choose email/Slack delivery and the warning period.",
        "tags": ["Organization"],
        "security": [
          {
            "BearerAuth": ["organizations:write"]
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UpdateNotificationSettingsRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Updated notification settings.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/NotificationSettings"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        }
      }
    },
    "/cli/login": {
      "get": {
        "operationId": "describeCliLogin",
        "summary": "Explain the CLI sign-in endpoint",
        "description": "Browsers sometimes open this URL. The endpoint accepts POST only, so this GET performs no action. It returns 405 with an Allow header and a short explanation. The body is HTML when the Accept header includes text/html, otherwise JSON. This endpoint does not require authentication.",
        "tags": ["CLI"],
        "security": [],
        "responses": {
          "405": {
            "description": "Method not allowed. The body explains how to sign in with the Strix CLI.",
            "headers": {
              "Allow": {
                "description": "Always `POST`.",
                "schema": { "type": "string" }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CliLoginBrowserHint"
                }
              },
              "text/html": {
                "schema": { "type": "string" }
              }
            }
          }
        }
      },
      "post": {
        "operationId": "startCliLogin",
        "summary": "Start a CLI sign-in",
        "description": "Start the OAuth 2.0 device authorization flow (RFC 8628). The response contains a user code and a verification URL. Show both to the user, then poll POST /cli/login/poll with the device code. This endpoint does not require authentication.",
        "tags": ["CLI"],
        "security": [],
        "responses": {
          "200": {
            "description": "Device authorization created.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CliDeviceAuthorization"
                }
              }
            }
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          },
          "429": {
            "description": "Too many requests from this client. Wait and retry.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          }
        }
      }
    },
    "/cli/login/poll": {
      "get": {
        "operationId": "describeCliLoginPoll",
        "summary": "Explain the CLI sign-in poll endpoint",
        "description": "Browsers sometimes open this URL. The endpoint accepts POST only, so this GET performs no action. It returns 405 with an Allow header and a short explanation. The body is HTML when the Accept header includes text/html, otherwise JSON. This endpoint does not require authentication.",
        "tags": ["CLI"],
        "security": [],
        "responses": {
          "405": {
            "description": "Method not allowed. The body tells the user to return to the terminal.",
            "headers": {
              "Allow": {
                "description": "Always `POST`.",
                "schema": { "type": "string" }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CliLoginBrowserHint"
                }
              },
              "text/html": {
                "schema": { "type": "string" }
              }
            }
          }
        }
      },
      "post": {
        "operationId": "pollCliLogin",
        "summary": "Poll a CLI sign-in",
        "description": "Exchange a device code for a personal API token. While the user has not approved the sign-in, the response is 400 with an `error` field of `authorization_pending` or `slow_down` — wait for the returned interval and poll again. `access_denied` and `expired_token` are terminal. On approval, the endpoint provisions the user and a default organization when needed, and returns a personal API token with a 90 day expiry. Set `interactive` to true to get a workspace list and a scope catalog instead of a token, then finish with POST /cli/login/complete. This endpoint does not require authentication.",
        "tags": ["CLI"],
        "security": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "device_code": {
                    "type": "string",
                    "description": "Device code from POST /cli/login. Never show this code to the user."
                  },
              "scopes": {
                    "type": "array",
                    "items": {
                      "$ref": "#/components/schemas/ApiV1Scope"
                    },
                "description": "Optional scopes for the minted token. The server always includes the minimum scopes scans:read, scans:write, and billing:read. The member's role limits the final set. Without this field, the server applies a default scope set."
              },
              "scope_profile": {
                "$ref": "#/components/schemas/CliScopeProfile"
              },
              "client_instance_id": {
                "type": "string",
                "minLength": 8,
                "maxLength": 128,
                "description": "Opaque stable identifier for this CLI installation. Send with device_name to reuse one session row on later sign-ins."
              },
              "device_name": {
                "type": "string",
                "minLength": 1,
                "maxLength": 80,
                "description": "Privacy-safe device label shown in API Access. Required with client_instance_id."
              },
              "interactive": {
                    "type": "boolean",
                    "description": "When true, approval returns `selection_required` with the user's workspaces, the scope catalog, and a short-lived `selection_token` instead of a token. Finish with POST /cli/login/complete."
                  }
                },
                "required": ["device_code"]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Sign-in complete, or a selection step when `interactive` is true. The `api_token` field contains the raw secret — store it securely.",
            "content": {
              "application/json": {
                "schema": {
                  "oneOf": [
                    {
                      "$ref": "#/components/schemas/CliLoginResult"
                    },
                    {
                      "$ref": "#/components/schemas/CliLoginSelection"
                    }
                  ]
                }
              }
            }
          },
          "400": {
            "description": "The device code is missing, pending, expired, or denied. The `error` field carries the OAuth error code.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "detail": {
                      "type": "string"
                    },
                    "error": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          },
          "429": {
            "description": "Too many requests from this client. Wait and retry.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          }
        }
      }
    },
    "/cli/login/complete": {
      "post": {
        "operationId": "completeCliLogin",
        "summary": "Complete an interactive CLI sign-in",
        "description": "Finish an interactive CLI sign-in after the user picks a workspace and scopes. Send the `selection_token` from the poll response. The workspace must be one of the user's memberships. The server always includes the minimum scopes and the member's role limits the final set. When `workspace_name` is present, the server checks that the user is an admin, mints the token, and then renames the chosen workspace. A failed rename does not fail the sign-in. The selection token expires after 10 minutes. This endpoint does not require authentication.",
        "tags": ["CLI"],
        "security": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "selection_token": {
                    "type": "string",
                    "description": "Selection token from POST /cli/login/poll with `interactive` set to true."
                  },
                  "organization_id": {
                    "type": "string",
                    "description": "Workspace that receives the token. Without this field, the server uses the user's first workspace."
                  },
                  "workspace_name": {
                    "type": "string",
                    "maxLength": 100,
                    "description": "New name for the chosen workspace. Use it when the workspace option has `has_default_name` set to true. The user must be an admin of the workspace. An empty value keeps the current name. When the value equals the current default name, the server records that the user chose the name and `onboarding.workspace_named` becomes true. If the rename fails, the sign-in still completes and `organization_name` shows the current name."
                  },
              "scopes": {
                    "type": "array",
                    "items": {
                      "$ref": "#/components/schemas/ApiV1Scope"
                    },
                "description": "Scopes the user selected. The server always includes the minimum scopes scans:read, scans:write, and billing:read. The member's role limits the final set."
              },
              "scope_profile": {
                "$ref": "#/components/schemas/CliScopeProfile"
              }
                },
                "required": ["selection_token"]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Sign-in complete. The `api_token` field contains the raw secret — store it securely.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CliLoginResult"
                }
              }
            }
          },
          "400": {
            "description": "The selection token or a requested scope is missing or invalid.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "401": {
            "description": "The selection token is invalid or expired. Start the sign-in again.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "403": {
            "description": "The user is not a member of the selected workspace, or `workspace_name` was sent and the user is not an admin (`not_an_admin`).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "429": {
            "description": "Too many requests from this client. Wait and retry.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        }
      }
    },
    "/billing/credits": {
      "get": {
        "operationId": "getCreditBalance",
        "summary": "Get the credit balance",
        "description": "Get the current top-up credit balance for the organization. Requires the billing:read scope.",
        "tags": ["Billing"],
        "security": [
          {
            "BearerAuth": ["billing:read"]
          }
        ],
        "responses": {
          "200": {
            "description": "Credit balance.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CreditBalance"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          }
        }
      }
    },
    "/billing/topup": {
      "post": {
        "operationId": "purchaseCredits",
        "summary": "Buy credits with a machine payment",
        "description": "Buy scan credits with the Machine Payments Protocol (MPP). Authenticate with `X-Strix-Authorization: Bearer <token>` because MPP uses the standard Authorization header for its payment credential. The first request without a payment credential returns HTTP 402 with a payment challenge. Pay the challenge with a Stripe agent wallet (https://link.com/agents), then retry the request with the payment credential. The user approves each payment in the Link app. If the user does not want a wallet, create a hosted checkout link with the billing checkout operation instead. A verified payment grants the credits one time and returns a receipt. Requires the billing:write scope and the admin role.",
        "tags": ["Billing"],
        "security": [
          {
            "StrixAuthorization": ["billing:write"]
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/TopupRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Payment verified and credits granted.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TopupResult"
                }
              }
            }
          },
          "402": {
            "description": "Payment required. The WWW-Authenticate header contains the MPP payment challenge. The body includes a wallet_setup field with instructions for wallet setup and the hosted checkout fallback."
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "503": {
            "$ref": "#/components/responses/ServiceUnavailable"
          }
        }
      }
    },
    "/billing/auto-topup": {
      "get": {
        "operationId": "getAutoTopupSettings",
        "summary": "Get automatic top-up settings",
        "description": "Get the automatic top-up settings for the organization. Requires the billing:read scope, an unscoped token, and the admin role.",
        "tags": ["Billing"],
        "security": [
          {
            "BearerAuth": ["billing:read"]
          }
        ],
        "responses": {
          "200": {
            "description": "Automatic top-up settings.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AutoTopupSettings"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          }
        }
      },
      "put": {
        "operationId": "updateAutoTopupSettings",
        "summary": "Update automatic top-up settings",
        "description": "Update the automatic top-up settings for the organization. Automatic top-up charges the saved payment method when a scan needs more credits. Requires the billing:write scope and the admin role.",
        "tags": ["Billing"],
        "security": [
          {
            "BearerAuth": ["billing:write"]
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "enabled": {
                    "description": "When true, Strix buys credits automatically when a scan needs more.",
                    "type": "boolean"
                  },
                  "topup_credits": {
                    "description": "Number of credits to buy on each automatic top-up.",
                    "type": "integer",
                    "minimum": 1,
                    "maximum": 10000
                  },
                  "monthly_cap_credits": {
                    "type": ["integer", "null"],
                    "description": "Maximum automatically purchased credits per calendar month. An omitted field keeps the stored cap. An explicit null removes the cap."
                  }
                },
                "required": ["enabled", "topup_credits"]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Updated settings.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AutoTopupSettings"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          }
        }
      }
    },
    "/cli/session": {
      "get": {
        "operationId": "getCliSession",
        "summary": "Get the current CLI session",
        "description": "Inspect the authenticated CLI device session, its effective scopes, saved scope preference, and immutable login consent ceiling. No API scope is required; the bearer must be a personal Strix CLI session.",
        "tags": ["CLI"],
        "security": [{ "BearerAuth": [] }],
        "responses": {
          "200": {
            "description": "Current CLI session.",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/CliSession" }
              }
            }
          },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "403": { "$ref": "#/components/responses/Forbidden" }
        }
      },
      "patch": {
        "operationId": "updateCliSessionScopes",
        "summary": "Change current CLI session scopes",
        "description": "Change the saved scope profile or custom requested scopes without exceeding the immutable ceiling approved at login. Broader access requires a new browser sign-in.",
        "tags": ["CLI"],
        "security": [{ "BearerAuth": [] }],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": { "$ref": "#/components/schemas/CreateWorkspaceTokenRequest" }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Updated CLI session.",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/CliSession" }
              }
            }
          },
          "400": { "$ref": "#/components/responses/BadRequest" },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "403": { "$ref": "#/components/responses/Forbidden" }
        }
      },
      "delete": {
        "operationId": "revokeCliSession",
        "summary": "Revoke the current CLI session",
        "description": "Revoke the authenticated CLI session itself. No token-management scope is required.",
        "tags": ["CLI"],
        "security": [{ "BearerAuth": [] }],
        "responses": {
          "200": {
            "description": "Session revoked.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": { "type": "boolean" },
                    "revoked_at": { "type": "string", "format": "date-time" }
                  },
                  "required": ["success", "revoked_at"]
                }
              }
            }
          },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "403": { "$ref": "#/components/responses/Forbidden" }
        }
      }
    },
    "/workspaces": {
      "get": {
        "operationId": "listWorkspaces",
        "summary": "List your workspaces",
        "description": "List the workspaces that the token owner is a member of. Requires a personal token; no API scope is required so a minimal CLI session can recover and switch.",
        "tags": ["Workspaces"],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "Workspace list.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/WorkspaceList"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          }
        }
      },
      "post": {
        "operationId": "createWorkspace",
        "summary": "Create a workspace",
        "description": "Create a workspace and make the token owner its admin. Requires a personal token and the organizations:write scope.",
        "tags": ["Workspaces"],
        "security": [
          {
            "BearerAuth": ["organizations:write"]
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreateWorkspaceRequest"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "The created workspace.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Workspace"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          }
        }
      }
    },
    "/workspaces/{organizationId}/token": {
      "post": {
        "operationId": "switchWorkspaceToken",
        "summary": "Switch the token to another workspace",
        "description": "Switch the authenticated personal token in place to a workspace that its owner is already a member of. The token row, bearer secret, expiry, saved scope preference, and immutable login consent ceiling are preserved, so the request is safe to retry after a lost response. The owner's current target-workspace role caps effective authority. No API scope is required and widening beyond the consent ceiling is rejected.",
        "tags": ["Workspaces"],
        "security": [
          {
            "BearerAuth": []
          }
        ],
        "parameters": [
          {
            "name": "organizationId",
            "in": "path",
            "required": true,
            "description": "The workspace identifier.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": false,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreateWorkspaceTokenRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The same token, switched to the selected workspace.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/WorkspaceToken"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "409": {
            "$ref": "#/components/responses/Conflict"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        }
      }
    },
    "/billing/checkout": {
      "post": {
        "operationId": "createBillingCheckout",
        "summary": "Create a checkout link",
        "description": "Create a hosted checkout link for a plan or a credit pack. A person must open the link and complete the payment. Requires the admin role and the billing:write scope.",
        "tags": ["Billing"],
        "security": [
          {
            "BearerAuth": ["billing:write"]
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreateCheckoutRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The checkout link.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CheckoutLink"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          }
        }
      }
    },
    "/billing/portal": {
      "post": {
        "operationId": "createBillingPortal",
        "summary": "Create a billing portal link",
        "description": "Create a hosted billing portal link. A person must open the link to change the payment method or the subscription. Requires the admin role and the billing:write scope.",
        "tags": ["Billing"],
        "security": [
          {
            "BearerAuth": ["billing:write"]
          }
        ],
        "responses": {
          "200": {
            "description": "The billing portal link.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PortalLink"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "409": {
            "$ref": "#/components/responses/Conflict"
          },
          "502": {
            "$ref": "#/components/responses/BadGateway"
          }
        }
      }
    },
    "/integrations/{provider}/install-url": {
      "post": {
        "operationId": "createIntegrationInstallUrl",
        "summary": "Create an installation link",
        "description": "Create the hosted installation link for one provider. A person must open the link and approve the access. The github provider returns a GitHub App installation link. The slack provider returns a Slack authorization link. Requires the admin role and the integrations:write scope.",
        "tags": ["Integrations"],
        "security": [
          {
            "BearerAuth": ["integrations:write"]
          }
        ],
        "parameters": [
          {
            "name": "provider",
            "in": "path",
            "required": true,
            "description": "The provider name.",
            "schema": {
              "type": "string",
              "enum": ["github", "slack"]
            }
          }
        ],
        "responses": {
          "200": {
            "description": "The installation link.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/InstallationLink"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          }
        }
      }
    }
  },
  "components": {
    "securitySchemes": {
      "BearerAuth": {
        "type": "http",
        "scheme": "bearer",
        "description": "API token obtained from the Tokens endpoint or CLI device login. Include as `Authorization: Bearer <token>`. Requests made with a managed CLI session also include `X-Strix-Workspace: <organization_id>` to pin a process to the workspace it started in; recovery endpoints report the current workspace after a concurrent switch."
      },
      "StrixAuthorization": {
        "type": "apiKey",
        "in": "header",
        "name": "X-Strix-Authorization",
        "description": "API token for operations where the standard Authorization header carries a protocol credential. Include as `X-Strix-Authorization: Bearer <token>`."
      }
    },
    "parameters": {
      "IdempotencyKey": {
        "name": "Idempotency-Key",
        "in": "header",
        "required": false,
        "description": "Opaque caller-generated key for at-most-once billable scan creation; use a high-entropy value such as a UUID. Reuse the exact same key only when retrying the exact same request. Completed keys are retained for at least 24 hours; an unfinished accepted worker receipt may be held longer until its downstream queue horizon is safely reconciled. A completed failure is terminal for that key. Keyed terminal responses echo Idempotency-Key and set Idempotency-Replayed to true only when returning a stored outcome.",
        "schema": {
          "type": "string",
          "minLength": 1,
          "maxLength": 200,
          "pattern": "^[A-Za-z0-9][A-Za-z0-9._:/=-]{0,199}$"
        }
      },
      "Page": {
        "description": "Page number of the result set. The first page is 1.",
        "name": "page",
        "in": "query",
        "schema": {
          "type": "integer",
          "minimum": 1,
          "default": 1
        }
      },
      "Limit": {
        "description": "Maximum number of items per page. The default is 20 and the maximum is 100.",
        "name": "limit",
        "in": "query",
        "schema": {
          "type": "integer",
          "minimum": 1,
          "maximum": 100,
          "default": 20
        }
      },
      "SortOrder": {
        "description": "Sort direction. Use `asc` for oldest first or `desc` for newest first.",
        "name": "sort_order",
        "in": "query",
        "schema": {
          "type": "string",
          "enum": ["asc", "desc"],
          "default": "desc"
        }
      },
      "SortBy_CreatedAt": {
        "description": "Field to sort by. Only `created_at` is supported.",
        "name": "sort_by",
        "in": "query",
        "schema": {
          "type": "string",
          "enum": ["created_at"],
          "default": "created_at"
        }
      },
      "ScanId": {
        "description": "UUID of the scan. Use the `id` field of a scan from `listScans`.",
        "name": "scanId",
        "in": "path",
        "required": true,
        "schema": {
          "type": "string",
          "format": "uuid"
        }
      },
      "VulnerabilityId": {
        "description": "ID of the vulnerability. Use the `id` field of a finding from `listVulnerabilities`.",
        "name": "vulnerabilityId",
        "in": "path",
        "required": true,
        "schema": {
          "type": "string"
        }
      },
      "ScheduleId": {
        "description": "ID of the schedule. Use the `id` field of a schedule from `listSchedules`.",
        "name": "scheduleId",
        "in": "path",
        "required": true,
        "schema": {
          "type": "string"
        }
      },
      "WebhookId": {
        "description": "UUID of the webhook. Use the `id` field of a webhook from `listWebhooks`.",
        "name": "webhookId",
        "in": "path",
        "required": true,
        "schema": {
          "type": "string",
          "format": "uuid"
        }
      }
    },
    "schemas": {
      "ScanStatus": {
        "type": "string",
        "enum": ["pending", "running", "completed", "failed", "cancelled"]
      },
      "VulnerabilitySeverity": {
        "type": "string",
        "enum": ["critical", "high", "medium", "low"]
      },
      "VulnerabilityStatus": {
        "type": "string",
        "enum": ["open", "in_progress", "snoozed", "fixed", "ignored", "not_affected"]
      },
      "FixEffort": {
        "type": "string",
        "enum": ["trivial", "low", "medium", "high"]
      },
      "ApiV1Scope": {
        "type": "string",
        "enum": [
          "scans:read",
          "scans:write",
          "vulnerabilities:read",
          "vulnerabilities:write",
          "dependencies:read",
          "schedules:read",
          "schedules:write",
          "assets:read",
          "assets:write",
          "organizations:read",
          "organizations:write",
          "members:read",
          "members:write",
          "invitations:read",
          "invitations:write",
          "webhooks:read",
          "webhooks:write",
          "tokens:write",
          "audit:read",
          "pr_reviews:read",
          "pr_reviews:write",
          "connectors:read",
          "connectors:write",
          "knowledge:read",
          "knowledge:write",
          "uploads:write",
          "integrations:read",
          "integrations:write",
          "chat:read",
          "chat:write",
          "scans:message",
          "analytics:read",
          "llm:read",
          "llm:write",
          "test_users:read",
          "test_users:write",
          "license:read",
          "supply_chain:read",
          "supply_chain:write",
          "billing:read",
          "billing:write"
        ]
      },
      "WebhookEvent": {
        "type": "string",
        "enum": [
          "scan.created",
          "scan.completed",
          "scan.failed",
          "scan.cancelled",
          "vulnerability.created",
          "vulnerability.status_changed",
          "vulnerability.severity_changed",
          "*"
        ]
      },
      "PaginationMeta": {
        "type": "object",
        "properties": {
          "page": {
            "type": "integer"
          },
          "limit": {
            "type": "integer"
          },
          "total_items": {
            "type": "integer"
          },
          "total_pages": {
            "type": "integer"
          },
          "has_next": {
            "type": "boolean"
          },
          "has_prev": {
            "type": "boolean"
          }
        },
        "required": [
          "page",
          "limit",
          "total_items",
          "total_pages",
          "has_next",
          "has_prev"
        ]
      },
      "Pagination": {
        "type": "object",
        "properties": {
          "page": {
            "type": "integer"
          },
          "limit": {
            "type": "integer"
          },
          "total": {
            "type": "integer"
          },
          "total_pages": {
            "type": "integer"
          }
        },
        "required": ["page", "limit", "total", "total_pages"]
      },
      "ScanFindings": {
        "type": "object",
        "properties": {
          "total": {
            "type": "integer"
          },
          "critical": {
            "type": "integer"
          },
          "high": {
            "type": "integer"
          },
          "medium": {
            "type": "integer"
          },
          "low": {
            "type": "integer"
          }
        },
        "required": ["total", "critical", "high", "medium", "low"]
      },
      "Repository": {
        "type": "object",
        "properties": {
          "url": {
            "type": "string"
          },
          "branch": {
            "type": "string"
          },
          "provider": {
            "type": "string"
          }
        },
        "required": ["url", "branch", "provider"]
      },
      "Scan": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "user_id": {
            "type": "string"
          },
          "title": {
            "type": "string"
          },
          "urls": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "repositories": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Repository"
            }
          },
          "domain_ids": {
            "type": "array",
            "items": {
              "type": "string",
              "format": "uuid"
            }
          },
          "repository_ids": {
            "type": "array",
            "items": {
              "type": "string",
              "format": "uuid"
            }
          },
          "schedule_id": {
            "type": ["string", "null"]
          },
          "scan_type": {
            "type": "string",
            "enum": ["whitebox", "blackbox"]
          },
          "connector_id": {
            "type": ["string", "null"]
          },
          "is_retest": {
            "type": "boolean"
          },
          "status": {
            "$ref": "#/components/schemas/ScanStatus"
          },
          "created_at": {
            "type": "string",
            "format": "date-time"
          },
          "updated_at": {
            "type": "string",
            "format": "date-time"
          },
          "completed_at": {
            "type": "string",
            "format": "date-time"
          },
          "duration": {
            "type": ["string", "null"]
          },
          "executive_summary": {
            "type": "string"
          },
          "methodology": {
            "type": "string"
          },
          "technical_analysis": {
            "type": "string"
          },
          "recommendations": {
            "type": "string"
          },
          "findings": {
            "$ref": "#/components/schemas/ScanFindings"
          },
          "org_knowledge_enabled": {
            "type": ["boolean", "null"]
          },
          "live_prompt_enabled": {
            "type": "boolean"
          },
          "live_prompt_ready": {
            "type": "boolean"
          },
          "max_budget_usd": {
            "type": ["number", "null"],
            "description": "Self-hosted only: per-scan LLM cost limit (USD), if one was set."
          },
          "auth_status": {
            "type": ["string", "null"],
            "description": "Whether the agent could log in with the provisioned test credentials, when any were configured: succeeded | failed."
          },
          "auth_failure_code": {
            "type": ["string", "null"],
            "description": "Category of the login failure (e.g. invalid_credentials, mfa_required_not_configured)."
          },
          "auth_detail": {
            "type": ["string", "null"],
            "description": "Short, secret-free explanation of the login outcome."
          },
          "auth_checked_at": {
            "type": ["string", "null"],
            "format": "date-time"
          },
          "cloud_connection_status": {
            "type": [
              "array",
              "null"
            ],
            "items": {
              "$ref": "#/components/schemas/CloudConnectionStatusEntry"
            },
            "description": "Attachment outcome for each cloud connection selected for the scan."
          },
          "cloud_connection_checked_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time",
            "description": "Time when the orchestrator checked the selected cloud connections."
          },
          "scan_tier": {
            "type": ["string", "null"],
            "enum": ["lite", "standard", "ultra", null],
            "description": "Scan tier the run used. A null value means the scan was launched without a tier."
          }
        },
        "required": ["id", "user_id", "title", "status", "created_at"]
      },
      "CloudConnectionStatusEntry": {
        "type": "object",
        "required": [
          "connection_id",
          "provider",
          "name",
          "status",
          "tool_count",
          "reason"
        ],
        "properties": {
          "connection_id": {
            "type": "string"
          },
          "provider": {
            "type": "string"
          },
          "name": {
            "type": "string"
          },
          "status": {
            "type": "string",
            "enum": [
              "attached",
              "failed"
            ]
          },
          "tool_count": {
            "type": [
              "integer",
              "null"
            ]
          },
          "reason": {
            "type": [
              "string",
              "null"
            ],
            "enum": [
              "not_ready",
              "duplicate_name",
              "connect_failed",
              "client_unavailable",
              null
            ]
          }
        }
      },
      "ScanCloudConnection": {
        "type": "object",
        "required": [
          "id",
          "slug",
          "provider",
          "label",
          "account",
          "notes",
          "applies_to_domain_ids",
          "applies_to_repository_ids",
          "project_name",
          "tool_hint"
        ],
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "slug": {
            "type": "string"
          },
          "provider": {
            "type": "string"
          },
          "label": {
            "type": "string"
          },
          "account": {
            "type": ["string", "null"]
          },
          "notes": {
            "type": ["string", "null"]
          },
          "applies_to_domain_ids": {
            "type": "array",
            "items": {
              "type": "string",
              "format": "uuid"
            }
          },
          "applies_to_repository_ids": {
            "type": "array",
            "items": {
              "type": "string",
              "format": "uuid"
            }
          },
          "project_name": {
            "type": ["string", "null"]
          },
          "tool_hint": {
            "type": ["string", "null"]
          }
        }
      },
      "CloudConnection": {
        "type": "object",
        "required": [
          "id",
          "provider",
          "externalAccountId",
          "accountLabel",
          "config",
          "notes",
          "appliesToDomainIds",
          "appliesToRepositoryIds",
          "connectedBy",
          "connectedAt",
          "credentialSourceId",
          "awaitingSignIn",
          "serverIdentity"
        ],
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "provider": {
            "type": "string",
            "enum": ["aws", "vercel", "supabase", "cloudflare", "google", "custom"]
          },
          "externalAccountId": {
            "type": ["string", "null"]
          },
          "accountLabel": {
            "type": ["string", "null"]
          },
          "config": {
            "type": ["object", "null"],
            "additionalProperties": true
          },
          "notes": {
            "type": ["string", "null"]
          },
          "appliesToDomainIds": {
            "type": "array",
            "items": {
              "type": "string",
              "format": "uuid"
            }
          },
          "appliesToRepositoryIds": {
            "type": "array",
            "items": {
              "type": "string",
              "format": "uuid"
            }
          },
          "connectedBy": {
            "type": ["string", "null"]
          },
          "connectedAt": {
            "type": "string",
            "format": "date-time"
          },
          "credentialSourceId": {
            "type": ["string", "null"],
            "format": "uuid"
          },
          "awaitingSignIn": {
            "type": "boolean",
            "description": "True for a custom MCP server connection whose OAuth sign-in has not finished. Scans do not use the connection until an admin signs in."
          },
          "serverIdentity": {
            "type": ["object", "null"],
            "description": "What a custom MCP server reported about itself after sign-in. Null for other providers and for servers that reported nothing. hasIcon is true when the server supplied an icon that the dashboard shows.",
            "required": ["title", "websiteUrl", "hasIcon", "iconVersion"],
            "properties": {
              "title": {
                "type": ["string", "null"]
              },
              "websiteUrl": {
                "type": ["string", "null"],
                "format": "uri"
              },
              "hasIcon": {
                "type": "boolean"
              },
              "iconVersion": {
                "type": ["string", "null"],
                "description": "Changes when the server reports a different icon. Null when hasIcon is false."
              }
            }
          }
        }
      },
      "AddCloudConnectionProjectRequest": {
        "type": "object",
        "required": ["project_ref"],
        "properties": {
          "project_ref": {
            "type": "string",
            "description": "Project reference to add."
          },
          "label": {
            "type": ["string", "null"],
            "description": "Optional label for the project connection."
          },
          "notes": {
            "type": ["string", "null"],
            "description": "Optional note for the project connection."
          },
          "applies_to_domain_ids": {
            "type": "array",
            "items": {
              "type": "string",
              "format": "uuid"
            },
            "description": "Domain ids that can use the connection."
          },
          "applies_to_repository_ids": {
            "type": "array",
            "items": {
              "type": "string",
              "format": "uuid"
            },
            "description": "Repository ids that can use the connection."
          }
        }
      },
      "ScanWithVulnerabilities": {
        "allOf": [
          {
            "$ref": "#/components/schemas/Scan"
          },
          {
            "type": "object",
            "properties": {
              "vulnerabilities": {
                "type": "array",
                "items": {
                  "$ref": "#/components/schemas/Vulnerability"
                }
              },
              "cloud_connections": {
                "type": "array",
                "items": {
                  "$ref": "#/components/schemas/ScanCloudConnection"
                }
              }
            }
          }
        ]
      },
      "PaginatedResponse_Scan": {
        "type": "object",
        "properties": {
          "items": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Scan"
            }
          },
          "meta": {
            "$ref": "#/components/schemas/PaginationMeta"
          }
        },
        "required": ["items", "meta"]
      },
      "RenameScanRequest": {
        "type": "object",
        "properties": {
          "title": {
            "type": "string",
            "minLength": 1,
            "maxLength": 120,
            "description": "New scan title. The server trims the value."
          }
        },
        "required": [
          "title"
        ]
      },
      "CreateScanRequest": {
        "type": "object",
        "description": "At least one target (domain_ids, repository_ids, upload_ids, or internal_targets) should be provided.",
        "properties": {
          "title": {
            "type": "string",
            "maxLength": 120,
            "description": "Custom scan title. When you set a title, the server does not generate one. The server trims the value."
          },
          "engagement_type": {
            "type": "string",
            "enum": [
              "code_review",
              "live_test",
              "internal_infra",
              "compliance_pentest"
            ],
            "description": "Which engagement type this run is. When omitted, source-only scopes infer `code_review`, domain scopes infer `live_test`, and internal targets infer `internal_infra`."
          },
          "domain_ids": {
            "description": "UUIDs of verified domains to test. Use `listDomains` to find them.",
            "type": "array",
            "items": {
              "type": "string",
              "format": "uuid"
            }
          },
          "domain_paths": {
            "type": "object",
            "additionalProperties": {
              "type": "array",
              "items": {
                "type": "string"
              }
            },
            "description": "Map of domain ID to specific paths to scan."
          },
          "repository_ids": {
            "description": "UUIDs of connected repositories to test. Use `listRepositories` to find them.",
            "type": "array",
            "items": {
              "type": "string",
              "format": "uuid"
            }
          },
          "repository_branches": {
            "type": "object",
            "additionalProperties": {
              "type": "string"
            },
            "description": "Map of repository ID to branch name."
          },
          "credentials": {
            "description": "Test accounts the agent logs in with during the scan. Stored encrypted and never returned. Prefer saved test users where available.",
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "username": {
                  "type": "string"
                },
                "password": {
                  "type": "string"
                },
                "notes": {
                  "type": "string"
                },
                "mfa_method": {
                  "type": "string",
                  "enum": ["none", "totp", "email_otp", "magic_link"],
                  "description": "Multi-factor method for authenticated scans."
                },
                "totp_secret": {
                  "type": "string",
                  "description": "Base32 TOTP secret, used when mfa_method is `totp`."
                },
                "mfa_email": {
                  "type": "string",
                  "format": "email",
                  "description": "Inbox to read one-time codes / magic links from, used when mfa_method is `email_otp` or `magic_link`."
                },
                "login_url": {
                  "type": "string",
                  "format": "uri",
                  "description": "Login page URL for this credential set."
                }
              },
              "required": ["username", "password"]
            }
          },
          "headers": {
            "description": "Custom HTTP headers the agent sends on every request, for example an API key header. Stored encrypted and never returned.",
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "name": {
                  "type": "string"
                },
                "value": {
                  "type": "string"
                },
                "notes": {
                  "type": "string"
                }
              },
              "required": ["name", "value"]
            }
          },
          "concerns": {
            "description": "Free-text security concerns to prioritize, for example `IDOR on the invoices API`.",
            "type": "string"
          },
          "focus": {
            "description": "Free-text areas of the target to test first, for example `the checkout flow`.",
            "type": "string"
          },
          "context": {
            "description": "Free-text background about the target that helps the agent, for example architecture notes or recent changes.",
            "type": "string"
          },
          "upload_ids": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Completed upload IDs to attach. A repository upload can be the sole target of a code review or provide white-box context for a domain pentest."
          },
          "connector_id": {
            "description": "ID of a network connector that gives the agent access to a private network. Use `listConnectors` to find it.",
            "type": "string"
          },
          "internal_targets": {
            "description": "Hosts or URLs inside a private network to test through the connector, for example `http://10.0.0.5:8080`.",
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "org_knowledge_enabled": {
            "description": "When true, the agent uses the organization knowledge base during the scan.",
            "type": "boolean"
          },
          "notify_on_completion": {
            "type": "boolean",
            "description": "Email the scan creator when the pentest finishes."
          },
          "notification_emails": {
            "type": "array",
            "items": {
              "type": "string",
              "format": "email"
            },
            "description": "Extra addresses to CC on the completion email. Validated only when notify_on_completion is true."
          },
          "scan_tier": {
            "type": "string",
            "enum": ["lite", "standard", "ultra"],
            "description": "Scan tier that sets how deep the pentest goes and which model quality it uses. The tier changes the credit price (lite ×0.3, standard ×0.75, ultra ×1). Defaults to ultra. Not applicable on self-hosted deployments, for organizations with raw model selection, and for organizations on the Enterprise plan."
          },
          "model_config_id": {
            "type": "string",
            "format": "uuid",
            "description": "Self-hosted only: run the scan with a named model config from Settings → LLM Models instead of the default assignment."
          },
          "max_budget_usd": {
            "type": "number",
            "exclusiveMinimum": 0,
            "maximum": 1000000,
            "description": "Self-hosted only: stop the pentest gracefully once total LLM spend reaches this amount (USD). Omit for no limit."
          }
        }
      },
      "CreateScanResponse": {
        "type": "object",
        "properties": {
          "scan_id": {
            "type": "string",
            "format": "uuid"
          },
          "title": {
            "type": "string"
          },
          "status": {
            "$ref": "#/components/schemas/ScanStatus"
          }
        },
        "required": ["scan_id", "title", "status"]
      },
      "CodeLocation": {
        "type": "object",
        "properties": {
          "file": {
            "type": "string"
          },
          "start_line": {
            "type": "integer"
          },
          "end_line": {
            "type": "integer"
          },
          "snippet": {
            "type": "string"
          },
          "label": {
            "type": "string"
          },
          "fix_before": {
            "type": "string"
          },
          "fix_after": {
            "type": "string"
          }
        },
        "required": ["file", "start_line"]
      },
      "CVSSBreakdown": {
        "type": "object",
        "properties": {
          "attack_vector": {
            "type": ["string", "null"]
          },
          "attack_complexity": {
            "type": ["string", "null"]
          },
          "privileges_required": {
            "type": ["string", "null"]
          },
          "user_interaction": {
            "type": ["string", "null"]
          },
          "scope": {
            "type": ["string", "null"]
          },
          "confidentiality": {
            "type": ["string", "null"]
          },
          "integrity": {
            "type": ["string", "null"]
          },
          "availability": {
            "type": ["string", "null"]
          }
        }
      },
      "LocationMeta": {
        "type": ["object", "null"],
        "properties": {
          "branch": {
            "type": "string"
          },
          "provider": {
            "type": "string"
          },
          "repo_url": {
            "type": "string"
          }
        }
      },
      "Vulnerability": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string"
          },
          "scan_id": {
            "type": ["string", "null"],
            "format": "uuid"
          },
          "pr_review_id": {
            "type": ["string", "null"],
            "format": "uuid"
          },
          "title": {
            "type": "string"
          },
          "description": {
            "type": "string"
          },
          "cve": {
            "type": ["string", "null"]
          },
          "cvss": {
            "type": ["number", "null"]
          },
          "created_at": {
            "type": "string",
            "format": "date-time"
          },
          "potential_risk_saving": {
            "type": ["number", "null"]
          },
          "risk_saving_description": {
            "type": ["string", "null"]
          },
          "status": {
            "$ref": "#/components/schemas/VulnerabilityStatus"
          },
          "severity": {
            "$ref": "#/components/schemas/VulnerabilitySeverity"
          },
          "impact": {
            "type": ["string", "null"]
          },
          "endpoint": {
            "type": ["string", "null"]
          },
          "method": {
            "type": ["string", "null"]
          },
          "target": {
            "type": ["string", "null"]
          },
          "technical_analysis": {
            "type": ["string", "null"]
          },
          "poc_description": {
            "type": ["string", "null"]
          },
          "poc_script_code": {
            "type": ["string", "null"]
          },
          "code_diff": {
            "type": ["string", "null"]
          },
          "code_file": {
            "type": ["string", "null"]
          },
          "code_before": {
            "type": ["string", "null"]
          },
          "code_after": {
            "type": ["string", "null"]
          },
          "cwe": {
            "type": ["array", "null"],
            "items": {
              "type": "string"
            }
          },
          "code_locations": {
            "type": ["array", "null"],
            "items": {
              "$ref": "#/components/schemas/CodeLocation"
            }
          },
          "remediation_steps": {
            "type": ["string", "null"]
          },
          "fix_pr_body": {
            "type": ["string", "null"]
          },
          "evidence": {
            "type": ["string", "null"]
          },
          "assumptions": {
            "type": ["string", "null"]
          },
          "fix_effort": {
            "$ref": "#/components/schemas/FixEffort"
          },
          "cvss_breakdown": {
            "oneOf": [
              {
                "$ref": "#/components/schemas/CVSSBreakdown"
              },
              {
                "type": "null"
              }
            ]
          },
          "status_changed_at": {
            "type": ["string", "null"],
            "format": "date-time"
          },
          "status_changed_by": {
            "type": ["string", "null"]
          },
          "status_note": {
            "type": ["string", "null"]
          },
          "original_severity": {
            "$ref": "#/components/schemas/VulnerabilitySeverity"
          },
          "severity_changed_at": {
            "type": ["string", "null"],
            "format": "date-time"
          },
          "severity_changed_by": {
            "type": ["string", "null"]
          },
          "severity_override_reason": {
            "type": ["string", "null"]
          },
          "retest_of_vulnerability_id": {
            "type": ["string", "null"]
          },
          "display_number": {
            "type": ["integer", "null"],
            "description": "Human-readable STRIX-ID number."
          },
          "location_meta": {
            "$ref": "#/components/schemas/LocationMeta"
          },
          "fix_pr_eligible": {
            "type": "boolean"
          },
          "fix_pr_reason": {
            "type": ["string", "null"]
          },
          "fix_pr_url": {
            "type": ["string", "null"]
          }
        },
        "required": [
          "id",
          "title",
          "description",
          "status",
          "severity",
          "created_at"
        ]
      },
      "VulnerabilityHttpExchangeRequest": {
        "type": "object",
        "description": "Metadata for one captured HTTP request.",
        "properties": {
          "run_id": {
            "type": "string"
          },
          "method": {
            "type": "string"
          },
          "host": {
            "type": "string"
          },
          "port": {
            "type": "integer"
          },
          "path": {
            "type": "string"
          },
          "query": {
            "type": "string"
          },
          "status_code": {
            "type": ["integer", "null"]
          },
          "response_time_ms": {
            "type": ["number", "null"]
          },
          "response_length": {
            "type": ["integer", "null"]
          },
          "is_tls": {
            "type": "boolean"
          },
          "in_scope": {
            "type": "boolean"
          },
          "file_extension": {
            "type": ["string", "null"]
          },
          "timestamp": {
            "type": "string",
            "format": "date-time"
          },
          "has_archived_exchange": {
            "type": "boolean"
          }
        },
        "required": [
          "run_id",
          "method",
          "host",
          "path",
          "timestamp",
          "has_archived_exchange"
        ]
      },
      "ArchivedHttpExchange": {
        "type": "object",
        "description": "Stored request and response text for one captured HTTP exchange.",
        "properties": {
          "raw_request": {
            "type": "string"
          },
          "raw_response": {
            "type": "string"
          },
          "request_truncated": {
            "type": "boolean"
          },
          "response_truncated": {
            "type": "boolean"
          }
        },
        "required": [
          "raw_request",
          "raw_response",
          "request_truncated",
          "response_truncated"
        ]
      },
      "VulnerabilityHttpExchange": {
        "type": "object",
        "description": "A captured HTTP exchange that supports a vulnerability.",
        "properties": {
          "run_id": {
            "type": "string"
          },
          "request_id": {
            "type": "string"
          },
          "ordinal": {
            "type": "integer",
            "minimum": 0
          },
          "lookup_state": {
            "type": "string",
            "enum": ["resolved", "not_found", "unavailable"]
          },
          "request": {
            "oneOf": [
              {
                "$ref": "#/components/schemas/VulnerabilityHttpExchangeRequest"
              },
              {
                "type": "null"
              }
            ]
          },
          "state": {
            "type": "string",
            "enum": ["archived", "unarchived", "unavailable", "not_found"]
          },
          "exchange": {
            "oneOf": [
              {
                "$ref": "#/components/schemas/ArchivedHttpExchange"
              },
              {
                "type": "null"
              }
            ]
          }
        },
        "required": [
          "run_id",
          "request_id",
          "ordinal",
          "lookup_state",
          "request"
        ]
      },
      "VulnerabilityHttpExchangesResponse": {
        "type": "object",
        "properties": {
          "exchanges": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/VulnerabilityHttpExchange"
            }
          }
        },
        "required": ["exchanges"]
      },
      "VulnerabilitySummary": {
        "type": "object",
        "description": "Abbreviated vulnerability returned in list endpoints.",
        "properties": {
          "id": {
            "type": "string"
          },
          "scan_id": {
            "type": "string",
            "format": "uuid"
          },
          "title": {
            "type": "string"
          },
          "target": {
            "type": ["string", "null"]
          },
          "severity": {
            "$ref": "#/components/schemas/VulnerabilitySeverity"
          },
          "cve": {
            "type": ["string", "null"]
          },
          "cvss": {
            "type": ["number", "null"]
          },
          "status": {
            "$ref": "#/components/schemas/VulnerabilityStatus"
          },
          "created_at": {
            "type": "string",
            "format": "date-time"
          },
          "display_number": {
            "type": ["integer", "null"]
          },
          "finding_type": {
            "type": "string",
            "enum": ["live_pentest", "code", "dependency"],
            "description": "Issue type bucket: dynamic finding from a live pentest, a code review finding, or a dependency CVE finding."
          },
          "dependency_metadata": {
            "type": ["object", "null"],
            "additionalProperties": true,
            "description": "Dependency findings only: the package details the scan recorded, such as `package`, `ecosystem`, `installed_version`, `fixed_version`, `manifest_path`, `introduced_by`, `reachability`, and the contextual CVSS rating."
          }
        },
        "required": [
          "id",
          "scan_id",
          "title",
          "severity",
          "status",
          "created_at"
        ]
      },
      "PaginatedResponse_VulnerabilitySummary": {
        "type": "object",
        "properties": {
          "items": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/VulnerabilitySummary"
            }
          },
          "meta": {
            "$ref": "#/components/schemas/PaginationMeta"
          }
        },
        "required": ["items", "meta"]
      },
      "UpdateVulnerabilityRequest": {
        "type": "object",
        "description": "At least one of `status` or `severity` must be provided.",
        "properties": {
          "status": {
            "description": "New triage status of the finding.",
            "$ref": "#/components/schemas/VulnerabilityStatus"
          },
          "note": {
            "type": "string",
            "description": "Optional note when changing status."
          },
          "severity": {
            "description": "New severity of the finding.",
            "$ref": "#/components/schemas/VulnerabilitySeverity"
          },
          "severity_reason": {
            "type": "string",
            "maxLength": 1000,
            "description": "Optional reason for the severity change."
          }
        }
      },
      "Domain": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "organization_id": {
            "type": "string"
          },
          "domain": {
            "type": "string"
          },
          "verified": {
            "type": "boolean"
          },
          "tags": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Enterprise asset labels used for RBAC scoping."
          },
          "business_unit": {
            "type": ["string", "null"],
            "description": "Enterprise asset label used for RBAC scoping."
          },
          "created_at": {
            "type": "string",
            "format": "date-time"
          },
          "last_scan_at": {
            "type": ["string", "null"],
            "format": "date-time"
          },
          "open_issue_count": {
            "type": "integer",
            "description": "The number of active findings (open, in_progress, snoozed) that are attributed to this asset. Dependency findings are not counted."
          },
          "open_issues": {
            "allOf": [{ "$ref": "#/components/schemas/ScanFindings" }],
            "description": "The same active findings as open_issue_count, grouped by severity."
          }
        },
        "required": [
          "id",
          "organization_id",
          "domain",
          "verified",
          "created_at"
        ]
      },
      "PaginatedResponse_Domain": {
        "type": "object",
        "properties": {
          "items": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Domain"
            }
          },
          "meta": {
            "$ref": "#/components/schemas/PaginationMeta"
          }
        },
        "required": ["items", "meta"]
      },
      "RepositoryAsset": {
        "type": "object",
        "description": "Repository metadata stored by Strix. Branch selection belongs to individual scans, schedules, and PR reviews; this object does not resolve a provider URL or default branch.",
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "organization_id": {
            "type": "string"
          },
          "full_name": {
            "type": "string"
          },
          "provider": {
            "type": "string"
          },
          "tags": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Enterprise asset labels used for RBAC scoping."
          },
          "business_unit": {
            "type": ["string", "null"],
            "description": "Enterprise asset label used for RBAC scoping."
          },
          "pr_review_enabled": {
            "type": "boolean",
            "description": "Whether automated PR reviews are enabled for this repository."
          },
          "pr_review_approvals_enabled": {
            "type": ["boolean", "null"],
            "description": "Tri-state per-repo override of the org PR review policy. true forces Strix to submit a GitHub approval on clean PRs for this repo, false forces it off, null inherits the org default (approve_clean_prs)."
          },
          "pr_review_non_blocking": {
            "type": ["boolean", "null"],
            "description": "Tri-state per-repo override of the org PR review policy. true forces findings to never block this repo's PRs (posted as comments only), false forces blocking on, null inherits the org default (block_on_findings)."
          },
          "pr_review_on_push": {
            "type": ["boolean", "null"],
            "description": "Tri-state per-repo override of the org PR review policy. true forces Strix to re-review this repo's PRs on every pushed commit, false forces it off (review only when the PR is opened), null inherits the org default (review_on_push)."
          },
          "created_at": {
            "type": "string",
            "format": "date-time"
          },
          "last_scan_at": {
            "type": ["string", "null"],
            "format": "date-time"
          },
          "open_issue_count": {
            "type": "integer",
            "description": "The number of active findings (open, in_progress, snoozed) that are attributed to this asset. Dependency findings are not counted."
          },
          "open_issues": {
            "allOf": [{ "$ref": "#/components/schemas/ScanFindings" }],
            "description": "The same active findings as open_issue_count, grouped by severity."
          }
        },
        "required": ["id", "organization_id", "full_name", "created_at"]
      },
      "PaginatedResponse_Repository": {
        "type": "object",
        "properties": {
          "items": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/RepositoryAsset"
            }
          },
          "meta": {
            "$ref": "#/components/schemas/PaginationMeta"
          }
        },
        "required": ["items", "meta"]
      },
      "ScanSchedule": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string"
          },
          "cron": {
            "type": "string",
            "description": "Cron expression (5-field)."
          },
          "isPaused": {
            "type": "boolean"
          },
          "createdAt": {
            "type": "string",
            "format": "date-time"
          },
          "organization_id": {
            "type": "string"
          },
          "created_by": {
            "type": "string"
          },
          "name": {
            "type": "string"
          },
          "timezone": {
            "type": "string",
            "description": "IANA timezone."
          },
          "supply_chain": {
            "type": "boolean",
            "description": "True when each fire runs supply-chain (dependency) scans."
          },
          "domain_ids": {
            "type": ["array", "null"],
            "items": {
              "type": "string"
            }
          },
          "repository_ids": {
            "type": ["array", "null"],
            "items": {
              "type": "string"
            }
          },
          "connector_id": {
            "type": ["string", "null"]
          },
          "internal_targets": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "concerns": {
            "type": ["string", "null"]
          },
          "focus": {
            "type": ["string", "null"]
          },
          "context": {
            "type": ["string", "null"]
          },
          "org_knowledge_enabled": {
            "type": ["boolean", "null"]
          },
          "last_run_status": {
            "type": ["string", "null"],
            "enum": ["ok", "skipped", "failing", null]
          },
          "last_run_error": {
            "type": ["string", "null"]
          },
          "last_run_code": {
            "type": ["string", "null"],
            "description": "Machine-readable cause of the last skipped/failing run, e.g. trial_scan_limit_reached"
          },
          "next_run_at": {
            "type": ["string", "null"],
            "format": "date-time"
          },
          "last_run_at": {
            "type": ["string", "null"],
            "format": "date-time"
          },
          "run_count": {
            "type": "integer"
          }
        },
        "required": [
          "id",
          "cron",
          "isPaused",
          "createdAt",
          "name",
          "timezone",
          "run_count"
        ]
      },
      "ScheduleRun": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "title": {
            "type": "string"
          },
          "status": {
            "$ref": "#/components/schemas/ScanStatus"
          },
          "created_at": {
            "type": "string",
            "format": "date-time"
          },
          "findings": {
            "$ref": "#/components/schemas/ScanFindings"
          }
        },
        "required": ["id", "title", "status", "created_at"]
      },
      "CreateScheduleRequest": {
        "description": "Recurring scan definition. Accepts every `CreateScanRequest` field plus the schedule fields.",
        "allOf": [
          {
            "$ref": "#/components/schemas/CreateScanRequest"
          },
          {
            "type": "object",
            "properties": {
              "cron_expression": {
                "type": "string",
                "description": "Cron expression, e.g. `0 9 * * 1`."
              },
              "timezone": {
                "type": "string",
                "description": "IANA timezone, e.g. `America/New_York`."
              },
              "name": {
                "type": "string"
              },
              "also_run_now": {
                "type": "boolean",
                "description": "If true, immediately launch a scan in addition to creating the schedule."
              },
              "supply_chain": {
                "type": "boolean",
                "description": "If true, each fire runs a free supply-chain (dependency) scan of each repository in `repository_ids`. Supply-chain schedules accept repository targets only."
              }
            },
            "required": ["cron_expression", "timezone"]
          }
        ]
      },
      "UpdateScheduleRequest": {
        "type": "object",
        "properties": {
          "action": {
            "type": "string",
            "enum": ["pause", "resume"],
            "description": "Pause or resume the schedule. Mutually exclusive with other fields."
          },
          "cron_expression": {
            "description": "New cron expression, for example `0 9 * * 1`.",
            "type": "string"
          },
          "timezone": {
            "description": "New IANA timezone for the cron expression, for example `America/New_York`.",
            "type": "string"
          },
          "name": {
            "description": "New display name of the schedule.",
            "type": "string"
          },
          "domain_ids": {
            "description": "Full replacement list of domain UUIDs to test on each run.",
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "domain_paths": {
            "description": "Map of domain ID to specific paths to scan on each run.",
            "type": "object",
            "additionalProperties": {
              "type": "array",
              "items": {
                "type": "string"
              }
            }
          },
          "repository_ids": {
            "description": "Full replacement list of repository UUIDs to test on each run.",
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "repository_branches": {
            "description": "Map of repository ID to the branch name to test on each run.",
            "type": "object",
            "additionalProperties": {
              "type": "string"
            }
          },
          "concerns": {
            "description": "Free-text security concerns to prioritize on each run.",
            "type": "string"
          },
          "focus": {
            "description": "Free-text areas of the target to test first on each run.",
            "type": "string"
          },
          "context": {
            "description": "Free-text background about the target for each run.",
            "type": "string"
          },
          "connector_id": {
            "description": "ID of the network connector each run uses to reach a private network.",
            "type": "string"
          },
          "internal_targets": {
            "description": "Full replacement list of private-network hosts or URLs to test through the connector.",
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "org_knowledge_enabled": {
            "description": "When true, each run uses the organization knowledge base.",
            "type": "boolean"
          },
          "max_budget_usd": {
            "type": ["number", "null"],
            "exclusiveMinimum": 0,
            "maximum": 1000000,
            "description": "Self-hosted only: per-run LLM cost limit (USD) applied to each fired scan. Send null to clear."
          },
          "scan_tier": {
            "type": ["string", "null"],
            "enum": ["lite", "standard", "ultra", null],
            "description": "Scan tier for each fired pentest. The tier changes the credit price of each run. Send null to reset to ultra. Not applicable on self-hosted deployments, for organizations with raw model selection, and for organizations on the Enterprise plan."
          },
          "credentials": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "username": {
                  "type": "string"
                },
                "password": {
                  "type": "string"
                },
                "notes": {
                  "type": "string"
                },
                "mfa_method": {
                  "type": "string",
                  "enum": ["none", "totp", "email_otp", "magic_link"],
                  "description": "Multi-factor method for authenticated scans."
                },
                "totp_secret": {
                  "type": "string",
                  "description": "Base32 TOTP secret, used when mfa_method is `totp`."
                },
                "mfa_email": {
                  "type": "string",
                  "format": "email",
                  "description": "Inbox to read one-time codes / magic links from, used when mfa_method is `email_otp` or `magic_link`."
                },
                "login_url": {
                  "type": "string",
                  "format": "uri",
                  "description": "Login page URL for this credential set."
                }
              },
              "required": ["username", "password"]
            },
            "description": "Replaces ALL stored manual credentials for the schedule. Omit to keep the stored credentials unchanged (the template endpoint returns their metadata only)."
          },
          "test_user_ids": {
            "type": "array",
            "items": {
              "type": "string",
              "format": "uuid"
            },
            "description": "Saved test users to authenticate with on each run."
          },
          "headers": {
            "type": "array",
            "description": "Full replacement set of custom headers. Stored header values are never returned by the template endpoint. Send keep_stored_value: true (with no value) to reuse the stored value of the existing schedule header with the same name.",
            "items": {
              "type": "object",
              "properties": {
                "name": {
                  "type": "string"
                },
                "value": {
                  "type": "string"
                },
                "notes": {
                  "type": "string"
                },
                "keep_stored_value": {
                  "type": "boolean",
                  "description": "Reuse the stored value of the existing header with the same name instead of sending one."
                }
              },
              "required": ["name"]
            }
          },
          "upload_ids": {
            "type": "array",
            "items": {
              "type": "string",
              "format": "uuid"
            },
            "description": "Replaces the schedule's uploads. Stored uploads the caller cannot access (hidden from the template for target-scoped actors) are preserved automatically."
          },
          "scope": {
            "type": "object",
            "description": "Per-run scope control applied to each fire. Send an empty object to clear the stored scope.",
            "properties": {
              "seeds": {
                "type": "array",
                "items": {
                  "type": "string"
                }
              },
              "allow": {
                "type": "array",
                "items": {
                  "$ref": "#/components/schemas/ScopeEntry"
                }
              },
              "visible": {
                "type": "array",
                "items": {
                  "$ref": "#/components/schemas/ScopeEntry"
                }
              },
              "deny": {
                "type": "array",
                "items": {
                  "$ref": "#/components/schemas/ScopeEntry"
                }
              }
            }
          },
          "notify_on_completion": {
            "type": "boolean",
            "description": "Email the schedule owner when each run completes."
          },
          "notification_emails": {
            "type": "array",
            "items": {
              "type": "string",
              "format": "email"
            },
            "description": "Extra addresses to CC on each run's completion email. Validated only when notify_on_completion is true."
          }
        }
      },
      "RbacScope": {
        "type": "object",
        "description": "An Enterprise RBAC asset restriction attached to an API token. target values identify a specific asset; tag and business_unit values match the corresponding asset metadata.",
        "properties": {
          "type": {
            "type": "string",
            "enum": ["target", "tag", "business_unit"]
          },
          "value": {
            "type": "string",
            "minLength": 1,
            "maxLength": 120,
            "pattern": "^[a-zA-Z0-9._:/@-]+$"
          }
        },
        "required": ["type", "value"],
        "additionalProperties": false
      },
      "ApiToken": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "type": {
            "type": "string",
            "enum": ["service", "personal"]
          },
          "organization_id": {
            "type": "string"
          },
          "user_id": {
            "type": ["string", "null"]
          },
          "name": {
            "type": "string"
          },
          "scopes": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ApiV1Scope"
            }
          },
          "rbac_scopes": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/RbacScope"
            },
            "description": "Enterprise RBAC asset restrictions on this token. An empty array means organization-wide asset access within the token's API scopes and the creator's current role."
          },
          "secret_prefix": {
            "type": "string"
          },
          "expires_at": {
            "type": ["string", "null"],
            "format": "date-time"
          },
          "last_used_at": {
            "type": ["string", "null"],
            "format": "date-time"
          },
          "revoked_at": {
            "type": ["string", "null"],
            "format": "date-time"
          },
          "created_by": {
            "type": "string"
          },
          "created_at": {
            "type": "string",
            "format": "date-time"
          },
          "updated_at": {
            "type": "string",
            "format": "date-time"
          },
          "credential_source": {
            "type": "string",
            "enum": ["api", "cli"],
            "description": "CLI rows are managed device sessions; API rows are ordinary user-created credentials."
          },
          "client_instance_id": {
            "type": ["string", "null"]
          },
          "device_name": {
            "type": ["string", "null"]
          },
          "scope_ceiling": {
            "type": "array",
            "items": { "$ref": "#/components/schemas/ApiV1Scope" }
          },
          "requested_scopes": {
            "type": "array",
            "items": { "$ref": "#/components/schemas/ApiV1Scope" }
          },
          "scope_profile": {
            "oneOf": [
              { "$ref": "#/components/schemas/CliScopeProfile" },
              { "type": "null" }
            ]
          },
          "last_workspace_switch_at": {
            "type": ["string", "null"],
            "format": "date-time"
          }
        },
        "required": [
          "id",
          "type",
          "name",
          "scopes",
          "rbac_scopes",
          "created_at",
          "credential_source"
        ]
      },
      "CreateTokenRequest": {
        "type": "object",
        "properties": {
          "type": {
            "description": "Token kind. `service` tokens belong to the organization, `personal` tokens act as the creating user.",
            "type": "string",
            "enum": ["service", "personal"]
          },
          "name": {
            "description": "Display name that identifies the token in the dashboard.",
            "type": "string"
          },
          "scopes": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ApiV1Scope"
            },
            "description": "When omitted or empty, service keys default to scans:read, scans:write, vulnerabilities:read, vulnerabilities:write, schedules:read, schedules:write, assets:read, webhooks:read, and webhooks:write. Personal keys default to the same first seven scopes without either webhook scope. Defaults and explicit requests are capped by the creator's current organization role; token-authenticated creators are additionally capped by the caller token's API and RBAC scopes. Only organization admins can create service keys."
          },
          "rbac_scopes": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/RbacScope"
            },
            "description": "Optional Enterprise RBAC asset restrictions. When omitted, a token-authenticated creator's restrictions are inherited; a browser-session creator defaults to an empty array (organization-wide asset access within the token's API scopes and role). Explicit restrictions must be a subset of the caller token's RBAC scopes."
          },
          "expires_at": {
            "type": "string",
            "format": "date-time",
            "description": "Explicit expiration. Mutually exclusive with expires_in_days."
          },
          "expires_in_days": {
            "type": "integer",
            "minimum": 1,
            "description": "Expiration as days from now. Personal tokens default to 90 days."
          }
        },
        "required": ["type", "name"]
      },
      "Webhook": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "organization_id": {
            "type": "string"
          },
          "url": {
            "type": "string",
            "format": "uri"
          },
          "events": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/WebhookEvent"
            }
          },
          "business_unit": {
            "type": ["string", "null"],
            "description": "When set, deliveries are restricted to events whose asset carries this business_unit. Null delivers for the whole organization."
          },
          "secret_prefix": {
            "type": "string"
          },
          "is_active": {
            "type": "boolean"
          },
          "last_success_at": {
            "type": ["string", "null"],
            "format": "date-time"
          },
          "last_failure_at": {
            "type": ["string", "null"],
            "format": "date-time"
          },
          "created_by": {
            "type": "string"
          },
          "created_at": {
            "type": "string",
            "format": "date-time"
          },
          "updated_at": {
            "type": "string",
            "format": "date-time"
          }
        },
        "required": ["id", "url", "events", "is_active", "created_at"]
      },
      "CreateWebhookRequest": {
        "type": "object",
        "properties": {
          "url": {
            "description": "HTTPS endpoint that receives the signed webhook deliveries.",
            "type": "string",
            "format": "uri"
          },
          "events": {
            "description": "Event names to subscribe to. Use `*` to receive every event.",
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/WebhookEvent"
            },
            "minItems": 1
          },
          "business_unit": {
            "type": ["string", "null"],
            "description": "Optional. Restrict deliveries to events whose asset carries this business_unit. Requires the Enterprise plan. Omit or null for an organization-wide subscription."
          },
          "is_active": {
            "description": "When false, the webhook is stored but no deliveries are sent.",
            "type": "boolean",
            "default": true
          }
        },
        "required": ["url", "events"]
      },
      "UpdateWebhookRequest": {
        "type": "object",
        "description": "At least one of url, events, is_active, business_unit, or rotate_secret must be provided.",
        "properties": {
          "url": {
            "description": "New HTTPS endpoint that receives the signed webhook deliveries.",
            "type": "string",
            "format": "uri"
          },
          "events": {
            "description": "Full replacement list of event names to subscribe to. Use `*` to receive every event.",
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/WebhookEvent"
            }
          },
          "business_unit": {
            "type": ["string", "null"],
            "description": "Set to a string to restrict deliveries to that business_unit (requires the Enterprise plan), or null to clear the scope (organization-wide)."
          },
          "is_active": {
            "description": "Set to false to pause deliveries, or true to resume them.",
            "type": "boolean"
          },
          "rotate_secret": {
            "type": "boolean",
            "description": "If true, generate and return a new signing secret."
          }
        }
      },
      "WebhookDelivery": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "subscription_id": {
            "type": "string",
            "format": "uuid"
          },
          "organization_id": {
            "type": "string"
          },
          "event_type": {
            "type": "string"
          },
          "payload": {
            "type": "object"
          },
          "status": {
            "type": "string"
          },
          "attempts": {
            "type": "integer"
          },
          "next_attempt_at": {
            "type": ["string", "null"],
            "format": "date-time"
          },
          "last_error": {
            "type": ["string", "null"]
          },
          "response_status": {
            "type": ["integer", "null"]
          },
          "response_body": {
            "type": ["string", "null"]
          },
          "sent_at": {
            "type": ["string", "null"],
            "format": "date-time"
          },
          "created_at": {
            "type": "string",
            "format": "date-time"
          },
          "updated_at": {
            "type": "string",
            "format": "date-time"
          }
        },
        "required": [
          "id",
          "subscription_id",
          "event_type",
          "status",
          "attempts",
          "created_at"
        ]
      },
      "PaginatedResponse_WebhookDelivery": {
        "type": "object",
        "properties": {
          "items": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/WebhookDelivery"
            }
          },
          "meta": {
            "$ref": "#/components/schemas/PaginationMeta"
          }
        },
        "required": ["items", "meta"]
      },
      "SuccessResponse": {
        "type": "object",
        "properties": {
          "success": {
            "type": "boolean"
          }
        },
        "required": ["success"]
      },
      "ErrorResponse": {
        "type": "object",
        "properties": {
          "detail": {
            "type": "string",
            "description": "Human-readable explanation of the error."
          },
          "code": {
            "type": "string",
            "description": "Stable machine-readable error code. `insufficient_scope` means the token does not hold the scope that this endpoint requires."
          },
          "required_scope": {
            "$ref": "#/components/schemas/ApiV1Scope",
            "description": "Scope that the caller must add to the token. Returned with the `insufficient_scope` code."
          },
          "docs": {
            "type": "string",
            "format": "uri",
            "description": "Documentation page that explains how to resolve the error."
          },
          "hint": {
            "type": "string",
            "description": "One instruction that resolves the error. For `insufficient_scope`, a CLI session gets the `strix cloud session scopes set full` or `strix cloud login --scope-profile full` command, and an API token gets the settings page where the user creates a token with the scope. When the owner's role cannot hold the scope, the hint asks for a role change instead."
          }
        },
        "required": ["detail"]
      },
      "InvalidIdempotencyKeyError": {
        "type": "object",
        "properties": {
          "detail": {
            "type": "string"
          },
          "code": {
            "const": "invalid_idempotency_key"
          },
          "terminal": {
            "const": true
          }
        },
        "required": ["detail", "code", "terminal"]
      },
      "IdempotencyKeyConflictError": {
        "type": "object",
        "properties": {
          "detail": {
            "type": "string"
          },
          "code": {
            "const": "idempotency_key_conflict"
          },
          "terminal": {
            "const": true
          }
        },
        "required": ["detail", "code", "terminal"]
      },
      "IdempotencyRequestInProgressError": {
        "type": "object",
        "properties": {
          "detail": {
            "type": "string"
          },
          "code": {
            "const": "idempotency_request_in_progress"
          },
          "retry_safe": {
            "const": true
          },
          "terminal": {
            "const": false
          }
        },
        "required": ["detail", "code", "retry_safe", "terminal"]
      },
      "IdempotencyOutcomeUnknownError": {
        "type": "object",
        "properties": {
          "detail": {
            "type": "string"
          },
          "code": {
            "const": "idempotency_outcome_unknown"
          },
          "retry_safe": {
            "const": true
          },
          "terminal": {
            "const": false
          },
          "scan_id": {
            "type": "string",
            "format": "uuid"
          }
        },
        "required": ["detail", "code", "retry_safe", "terminal", "scan_id"]
      },
      "IdempotencyAcceptedResponseUnavailableError": {
        "type": "object",
        "description": "The scan reached durable acceptance, but the endpoint resource needed to reconstruct its original response was removed. The launch is terminal and must not be repeated with a new key.",
        "properties": {
          "detail": {
            "type": "string"
          },
          "code": {
            "const": "idempotency_accepted_response_unavailable"
          },
          "terminal": {
            "const": true
          },
          "scan_id": {
            "type": "string",
            "format": "uuid"
          }
        },
        "required": ["detail", "code", "terminal", "scan_id"]
      },
      "IdempotencyAttemptAbandonedError": {
        "type": "object",
        "description": "The prior attempt did not reach durable acceptance. This key is terminal; a deliberate new attempt requires a new key.",
        "properties": {
          "detail": {
            "type": "string"
          },
          "code": {
            "const": "idempotency_attempt_abandoned"
          },
          "terminal": {
            "const": true
          },
          "scan_id": {
            "type": "string",
            "format": "uuid"
          }
        },
        "required": ["detail", "code", "terminal", "scan_id"]
      },
      "DomainAssetType": {
        "type": "string",
        "enum": ["web_app", "api", "attack_surface"]
      },
      "VerificationMethods": {
        "type": "object",
        "properties": {
          "dns": {
            "type": "object",
            "properties": {
              "record_name": {
                "type": "string"
              },
              "record_value": {
                "type": "string"
              }
            },
            "required": ["record_name", "record_value"]
          },
          "file": {
            "type": "object",
            "properties": {
              "url": {
                "type": "string"
              },
              "file_content": {
                "type": "string"
              }
            },
            "required": ["url", "file_content"]
          },
          "meta_tag": {
            "type": "object",
            "properties": {
              "tag": {
                "type": "string"
              }
            },
            "required": ["tag"]
          },
          "hash": {
            "type": "string"
          }
        },
        "required": ["dns", "file", "meta_tag", "hash"]
      },
      "CreateDomainRequest": {
        "type": "object",
        "properties": {
          "domain": {
            "description": "Hostname to add, for example `app.example.com`. Do not include a scheme or path.",
            "type": "string"
          },
          "asset_type": {
            "description": "Kind of asset the domain is. Use `web_app` for browser applications, `api` for HTTP APIs, and `attack_surface` for external discovery.",
            "$ref": "#/components/schemas/DomainAssetType"
          },
          "context": {
            "description": "Free-text background about the domain that the agent uses on every scan. Send null to clear it.",
            "type": ["string", "null"]
          },
          "tags": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Enterprise asset labels for RBAC scoping. Requires the Enterprise plan."
          },
          "business_unit": {
            "type": ["string", "null"],
            "description": "Enterprise asset label for RBAC scoping. Requires the Enterprise plan."
          }
        },
        "required": ["domain", "asset_type"]
      },
      "UpdateDomainRequest": {
        "type": "object",
        "description": "At least one of context, tags, or business_unit must be provided. Tags and business_unit require the Enterprise plan.",
        "properties": {
          "context": {
            "description": "New free-text background about the domain for the agent. Send null to clear it.",
            "type": ["string", "null"]
          },
          "tags": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Replaces the domain's tags. Requires the Enterprise plan."
          },
          "business_unit": {
            "type": ["string", "null"],
            "description": "Sets or clears the business_unit. Requires the Enterprise plan."
          }
        }
      },
      "DomainCreateResponse": {
        "type": "object",
        "properties": {
          "domain": {
            "$ref": "#/components/schemas/Domain"
          },
          "status": {
            "type": "string",
            "enum": ["added", "exists"]
          },
          "reachable": {
            "type": "boolean"
          },
          "verification": {
            "$ref": "#/components/schemas/VerificationMethods"
          }
        },
        "required": ["domain", "status", "reachable", "verification"]
      },
      "DomainVerificationResponse": {
        "type": "object",
        "description": "Result of a verification attempt. A 200 status does not mean success. Read `verified` or `status`.",
        "properties": {
          "domain": {
            "$ref": "#/components/schemas/Domain"
          },
          "verified": {
            "type": "boolean",
            "description": "True only when Strix confirmed ownership of the domain."
          },
          "status": {
            "type": "string",
            "enum": ["verified", "pending"],
            "description": "`pending` means no verification record was found yet. Add a record, then call this endpoint again."
          },
          "detail": {
            "type": "string",
            "description": "Human-readable result and the next action."
          },
          "verification_method": {
            "type": "string",
            "enum": ["allowlist", "existing", "dns", "file", "meta_tag", "email"],
            "description": "The method that confirmed ownership. Present only when `verified` is true."
          },
          "next_steps": {
            "type": "array",
            "items": { "type": "string" },
            "description": "One instruction per verification method, plus the retry command. Present only when `status` is `pending`."
          },
          "verification": {
            "$ref": "#/components/schemas/VerificationMethods",
            "description": "The DNS, file, and meta tag records for this domain. Present only when `status` is `pending`."
          }
        },
        "required": ["domain", "verified", "status", "detail"]
      },
      "CreateRepositoryRequest": {
        "type": "object",
        "properties": {
          "full_name": {
            "type": "string"
          },
          "provider": {
            "type": "string",
            "default": "github"
          },
          "installation_id": {
            "type": ["integer", "null"]
          },
          "tags": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Enterprise asset labels for RBAC scoping. Requires the Enterprise plan."
          },
          "business_unit": {
            "type": ["string", "null"],
            "description": "Enterprise asset label for RBAC scoping. Requires the Enterprise plan."
          }
        },
        "required": ["full_name"]
      },
      "RepositoriesCreateResponse": {
        "type": "object",
        "properties": {
          "repositories": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/RepositoryAsset"
            }
          }
        },
        "required": ["repositories"]
      },
      "UpdateRepositoryRequest": {
        "type": "object",
        "properties": {
          "pr_review_enabled": {
            "description": "When true, Strix reviews pull requests opened in this repository.",
            "type": "boolean"
          },
          "pr_review_approvals_enabled": {
            "type": ["boolean", "null"],
            "description": "Tri-state per-repo override of the org PR review policy. true forces Strix to submit a GitHub approval on clean PRs for this repo, false forces it off, null inherits the org default (approve_clean_prs)."
          },
          "pr_review_non_blocking": {
            "type": ["boolean", "null"],
            "description": "Tri-state per-repo override of the org PR review policy. true forces findings to never block this repo's PRs (posted as comments only), false forces blocking on, null inherits the org default (block_on_findings)."
          },
          "pr_review_on_push": {
            "type": ["boolean", "null"],
            "description": "Tri-state per-repo override of the org PR review policy. true forces Strix to re-review this repo's PRs on every pushed commit, false forces it off (review only when the PR is opened), null inherits the org default (review_on_push)."
          },
          "tags": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Replaces the repository's tags. Requires the Enterprise plan."
          },
          "business_unit": {
            "type": ["string", "null"],
            "description": "Sets or clears the business_unit. Requires the Enterprise plan."
          }
        }
      },
      "Organization": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string"
          },
          "name": {
            "type": "string"
          },
          "createdAt": {
            "type": "string",
            "format": "date-time"
          }
        },
        "required": ["id", "name"]
      },
      "UpdateOrganizationRequest": {
        "type": "object",
        "properties": {
          "name": {
            "description": "New display name of the organization.",
            "type": "string",
            "maxLength": 100
          }
        },
        "required": ["name"]
      },
      "OrgRole": {
        "type": "string",
        "enum": ["admin", "analyst", "viewer"]
      },
      "OrgRoleScope": {
        "type": "object",
        "properties": {
          "type": {
            "type": "string",
            "enum": ["target", "tag", "business_unit"]
          },
          "value": {
            "type": "string"
          }
        },
        "required": ["type", "value"]
      },
      "OrganizationMember": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string"
          },
          "userId": {
            "type": "string"
          },
          "email": {
            "type": "string"
          },
          "firstName": {
            "type": ["string", "null"]
          },
          "lastName": {
            "type": ["string", "null"]
          },
          "avatarUrl": {
            "type": ["string", "null"]
          },
          "role": {
            "$ref": "#/components/schemas/OrgRole"
          },
          "scopes": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/OrgRoleScope"
            }
          },
          "status": {
            "type": "string",
            "enum": ["active", "pending", "inactive"]
          },
          "joinedAt": {
            "type": "string"
          }
        },
        "required": ["id", "userId", "email", "role", "status"]
      },
      "MembersListResponse": {
        "type": "object",
        "properties": {
          "members": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/OrganizationMember"
            }
          }
        },
        "required": ["members"]
      },
      "InviteMemberRequest": {
        "type": "object",
        "properties": {
          "email": {
            "description": "Email address of the person to invite.",
            "type": "string",
            "format": "email"
          },
          "role": {
            "description": "Role the member gets after accepting. `admin` manages the organization, `analyst` triages findings, `viewer` is read-only.",
            "$ref": "#/components/schemas/OrgRole"
          },
          "scopes": {
            "description": "Enterprise RBAC asset restrictions for the member. Omit for access to every asset.",
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/OrgRoleScope"
            }
          }
        },
        "required": ["email"]
      },
      "UpdateMemberRoleRequest": {
        "type": "object",
        "properties": {
          "role": {
            "description": "New role of the member. `admin` manages the organization, `analyst` triages findings, `viewer` is read-only.",
            "$ref": "#/components/schemas/OrgRole"
          },
          "scopes": {
            "description": "Full replacement list of Enterprise RBAC asset restrictions. Omit for access to every asset.",
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/OrgRoleScope"
            }
          }
        },
        "required": ["role"]
      },
      "MemberRoleUpdateResponse": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string"
          },
          "role": {
            "$ref": "#/components/schemas/OrgRole"
          },
          "scopes": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/OrgRoleScope"
            }
          }
        },
        "required": ["id", "role"]
      },
      "Invitation": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string"
          },
          "email": {
            "type": "string",
            "format": "email"
          },
          "role": {
            "$ref": "#/components/schemas/OrgRole"
          },
          "scopes": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/OrgRoleScope"
            }
          },
          "state": {
            "type": "string",
            "enum": ["pending", "accepted", "revoked", "expired"]
          },
          "expiresAt": {
            "type": "string",
            "format": "date-time"
          },
          "createdAt": {
            "type": "string",
            "format": "date-time"
          }
        },
        "required": ["id", "email", "role", "state", "expiresAt", "createdAt"]
      },
      "InvitationsListResponse": {
        "type": "object",
        "properties": {
          "invitations": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Invitation"
            }
          }
        },
        "required": ["invitations"]
      },
      "SeverityCounts": {
        "type": "object",
        "properties": {
          "total": {
            "type": "integer"
          },
          "critical": {
            "type": "integer"
          },
          "high": {
            "type": "integer"
          },
          "medium": {
            "type": "integer"
          },
          "low": {
            "type": "integer"
          }
        },
        "required": ["total", "critical", "high", "medium", "low"]
      },
      "ScanFrequencyDay": {
        "type": "object",
        "description": "Number of scans started on a given calendar day (caller timezone).",
        "properties": {
          "date": {
            "type": "string",
            "format": "date",
            "description": "YYYY-MM-DD."
          },
          "count": {
            "type": "integer"
          }
        },
        "required": ["date", "count"]
      },
      "ConnectorStatus": {
        "type": "string",
        "enum": ["pending", "healthy", "degraded", "inactive", "down"]
      },
      "NetworkConnector": {
        "type": "object",
        "description": "Network connector (sensitive Tailscale fields are never returned).",
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "name": {
            "type": "string"
          },
          "last_status": {
            "$ref": "#/components/schemas/ConnectorStatus"
          },
          "last_status_checked_at": {
            "type": ["string", "null"],
            "format": "date-time"
          },
          "created_at": {
            "type": "string",
            "format": "date-time"
          }
        },
        "required": ["id", "name", "last_status", "created_at"]
      },
      "CreateConnectorRequest": {
        "type": "object",
        "properties": {
          "name": {
            "type": "string",
            "description": "Human-readable connector name."
          }
        },
        "required": ["name"]
      },
      "CreateConnectorResponse": {
        "type": "object",
        "properties": {
          "connector": {
            "$ref": "#/components/schemas/NetworkConnector"
          },
          "docker_command": {
            "type": "string",
            "description": "Ready-to-run `docker run` command that brings the connector online inside the customer network."
          }
        },
        "required": ["connector", "docker_command"]
      },
      "ChatSummary": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "title": {
            "type": ["string", "null"]
          },
          "status": {
            "type": "string"
          },
          "created_at": {
            "type": "string",
            "format": "date-time"
          },
          "last_message_at": {
            "type": ["string", "null"],
            "format": "date-time"
          }
        },
        "required": ["id", "status", "created_at"]
      },
      "Chat": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "title": {
            "type": ["string", "null"]
          },
          "status": {
            "type": "string"
          },
          "workspace_state": {
            "type": "string",
            "enum": ["starting", "running", "asleep", "ended"],
            "description": "State of the chat workspace. `starting` means the workspace is not ready yet. `running` means the workspace is ready. `asleep` means the workspace stopped after an idle period and keeps its files and its memory. The next message wakes the workspace. `ended` means the workspace is gone, and the conversation stays readable."
          },
          "run_id": {
            "type": ["string", "null"]
          },
          "sandbox_api_url": {
            "type": "boolean",
            "description": "True when the chat has a live sandbox attached. The URL itself is never exposed."
          },
          "created_at": {
            "type": "string",
            "format": "date-time"
          },
          "updated_at": {
            "type": "string",
            "format": "date-time"
          },
          "last_message_at": {
            "type": ["string", "null"],
            "format": "date-time"
          }
        },
        "required": ["id", "status", "created_at"]
      },
      "ChatRepoRef": {
        "type": "object",
        "properties": {
          "repoId": {
            "type": "string",
            "description": "Connected repository id to attach as context."
          },
          "branch": {
            "type": "string"
          }
        },
        "required": ["repoId"]
      },
      "StartChatRequest": {
        "type": "object",
        "description": "Start a new chat. `application/json` is shown here. To attach files, send `multipart/form-data` instead.",
        "properties": {
          "message": {
            "description": "First instruction for the agent, in natural language.",
            "type": "string"
          },
          "repos": {
            "description": "Connected repositories to attach as context for the chat.",
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ChatRepoRef"
            }
          },
          "images": {
            "description": "Image URLs to attach to the message.",
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "url": {
                  "type": "string"
                }
              },
              "required": ["url"]
            }
          },
          "domain_ids": {
            "type": "array",
            "items": {
              "type": "string",
              "format": "uuid"
            },
            "description": "Verified organization domain ids to scope the chat to. Narrowing only: the agent is authorized to test only these domains (and their subdomains). Omit for organization-wide authorization."
          }
        },
        "required": ["message"]
      },
      "SendChatMessageRequest": {
        "type": "object",
        "description": "Send a `message`, or set `cancel_current` or `stop_agent` to true. Attach `repos` or `images` as context for the message.",
        "properties": {
          "message": {
            "description": "Next instruction for the agent, in natural language.",
            "type": "string",
            "minLength": 1
          },
          "cancel_current": {
            "type": "boolean",
            "description": "Cancel the in-flight agent turn before sending."
          },
          "stop_agent": {
            "type": "boolean",
            "description": "Park the target agent and its descendants (leaves first) instead of only cancelling the current turn. Parked agents resume when messaged again. Send with agent_id and no message to stop a subagent."
          },
          "repos": {
            "description": "Additional connected repositories to attach as context.",
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ChatRepoRef"
            }
          },
          "images": {
            "description": "Image URLs to attach to the message.",
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "url": {
                  "type": "string"
                }
              },
              "required": ["url"]
            }
          },
          "agent_id": {
            "type": "string",
            "description": "Deliver the message to this subagent instead of the chat's root agent."
          }
        },
        "anyOf": [
          {
            "required": ["message"]
          },
          {
            "required": ["cancel_current"],
            "properties": {
              "cancel_current": {
                "const": true
              }
            }
          },
          {
            "required": ["stop_agent"],
            "properties": {
              "stop_agent": {
                "const": true
              }
            }
          }
        ]
      },
      "PrReviewFindings": {
        "description": "PR-wide finding counts used by list and detail views. They combine the selected/latest run's reconciled findings with deduplicated fixed findings from earlier runs of the same pull request. The top-level severity totals cover that aggregate; `unresolved` covers findings still open or in progress, `snoozed` counts deliberately deferred findings, and `fixed` includes fixed history across runs.",
        "allOf": [
          {
            "$ref": "#/components/schemas/SeverityCounts"
          }
        ],
        "type": "object",
        "properties": {
          "unresolved": {
            "$ref": "#/components/schemas/SeverityCounts"
          },
          "snoozed": {
            "type": "integer"
          },
          "fixed": {
            "type": "integer"
          }
        },
        "required": ["unresolved", "snoozed", "fixed"]
      },
      "PrReview": {
        "type": "object",
        "description": "One PR review run plus PR-wide reconciled finding counts in `findings`.",
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "organization_id": {
            "type": "string"
          },
          "user_id": {
            "type": ["string", "null"]
          },
          "provider": {
            "type": "string",
            "enum": ["github", "gitlab", "bitbucket"]
          },
          "installation_id": {
            "type": "integer"
          },
          "status": {
            "type": "string",
            "enum": ["pending", "running", "completed", "posting", "posted", "failed"]
          },
          "repository_full_name": {
            "type": "string"
          },
          "pr_number": {
            "type": "integer"
          },
          "pr_title": {
            "type": ["string", "null"]
          },
          "pr_url": {
            "type": ["string", "null"]
          },
          "head_branch": {
            "type": "string",
            "description": "Source branch reviewed by this run."
          },
          "base_branch": {
            "type": ["string", "null"],
            "description": "Destination branch for the pull request. Null when the provider did not supply it."
          },
          "head_sha": {
            "type": "string"
          },
          "base_sha": {
            "type": ["string", "null"]
          },
          "start_sha": {
            "type": ["string", "null"]
          },
          "pr_author": {
            "type": ["string", "null"]
          },
          "trigger": {
            "type": "string",
            "enum": ["webhook", "manual"]
          },
          "mode": {
            "type": ["string", "null"],
            "enum": ["review", "verify_base", null]
          },
          "pr_state": {
            "type": ["string", "null"],
            "enum": ["open", "merged", "closed", null],
            "description": "The pull request's own lifecycle, stamped when a review starts and kept live by provider webhooks. Null on older reviews."
          },
          "pr_merged_at": {
            "type": ["string", "null"],
            "format": "date-time"
          },
          "summary": {
            "type": ["string", "null"]
          },
          "verdict": {
            "type": ["string", "null"],
            "enum": ["approve", "comment", "request_changes", null]
          },
          "findings_count": {
            "type": "integer",
            "minimum": 0,
            "description": "Trigger-maintained count for this individual review run. Prefer the nested `findings.total` field for the PR-wide aggregate shown by list and detail views."
          },
          "open_findings_count": {
            "type": "integer",
            "minimum": 0,
            "description": "Trigger-maintained unresolved count for this individual review run. Prefer nested `findings.unresolved.total` for the PR-wide actionable aggregate."
          },
          "max_open_score": {
            "type": ["number", "null"]
          },
          "duration": {
            "type": ["string", "null"]
          },
          "created_at": {
            "type": "string",
            "format": "date-time"
          },
          "updated_at": {
            "type": "string",
            "format": "date-time"
          },
          "posted_at": {
            "type": ["string", "null"],
            "format": "date-time"
          },
          "findings": {
            "$ref": "#/components/schemas/PrReviewFindings"
          }
        },
        "required": [
          "id",
          "organization_id",
          "user_id",
          "provider",
          "installation_id",
          "status",
          "repository_full_name",
          "pr_number",
          "pr_title",
          "pr_url",
          "head_branch",
          "base_branch",
          "head_sha",
          "base_sha",
          "start_sha",
          "pr_author",
          "trigger",
          "mode",
          "pr_state",
          "pr_merged_at",
          "summary",
          "verdict",
          "findings_count",
          "open_findings_count",
          "max_open_score",
          "duration",
          "created_at",
          "updated_at",
          "posted_at",
          "findings"
        ]
      },
      "PrReviewVulnerability": {
        "type": "object",
        "description": "One deduplicated finding in the pull request's cross-run history.",
        "properties": {
          "id": { "type": "string" },
          "title": { "type": "string" },
          "description": { "type": "string" },
          "severity": { "$ref": "#/components/schemas/VulnerabilitySeverity" },
          "status": { "$ref": "#/components/schemas/VulnerabilityStatus" },
          "cve": { "type": ["string", "null"] },
          "cvss": { "type": ["number", "null"] },
          "created_at": { "type": "string", "format": "date-time" },
          "target": { "type": ["string", "null"] },
          "endpoint": { "type": ["string", "null"] },
          "method": { "type": ["string", "null"] },
          "code_locations": {
            "type": ["array", "null"],
            "items": { "type": "object", "additionalProperties": true }
          }
        },
        "required": [
          "id",
          "title",
          "description",
          "severity",
          "status",
          "cve",
          "cvss",
          "created_at",
          "target",
          "endpoint",
          "method",
          "code_locations"
        ]
      },
      "PrReviewDetail": {
        "allOf": [
          { "$ref": "#/components/schemas/PrReview" },
          {
            "type": "object",
            "properties": {
              "vulnerabilities": {
                "type": "array",
                "items": { "$ref": "#/components/schemas/PrReviewVulnerability" }
              }
            },
            "required": ["vulnerabilities"]
          }
        ]
      },
      "StartPrReviewResponse": {
        "type": "object",
        "properties": {
          "review_id": { "type": "string", "format": "uuid" },
          "status": {
            "type": "string",
            "enum": ["pending", "running", "completed", "posting", "posted", "failed"]
          }
        },
        "required": ["review_id", "status"]
      },
      "PaginatedResponse_PrReview": {
        "type": "object",
        "properties": {
          "items": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/PrReview"
            }
          },
          "meta": {
            "$ref": "#/components/schemas/PaginationMeta"
          },
          "counts": {
            "$ref": "#/components/schemas/PrReviewListCounts"
          }
        },
        "required": ["items", "meta"]
      },
      "PrReviewListCounts": {
        "type": "object",
        "description": "Review counts per disposition group. The deprecated keys keep their original semantics: `active`/`running` = runs currently in flight, `completed` = terminal reviews with nothing unresolved (regardless of the PR's own state).",
        "properties": {
          "all": {
            "type": "integer"
          },
          "open": {
            "type": "integer"
          },
          "attention": {
            "type": "integer"
          },
          "merged_open": {
            "type": "integer"
          },
          "passed": {
            "type": "integer"
          },
          "active": {
            "type": "integer",
            "deprecated": true
          },
          "running": {
            "type": "integer",
            "deprecated": true
          },
          "completed": {
            "type": "integer",
            "deprecated": true
          }
        },
        "required": ["all", "open", "attention", "merged_open", "passed"]
      },
      "PrReviewCaughtFinding": {
        "type": "object",
        "description": "One security issue that a PR review caught, with its pull request context.",
        "properties": {
          "id": {
            "type": "string"
          },
          "title": {
            "type": "string"
          },
          "severity": {
            "$ref": "#/components/schemas/VulnerabilitySeverity"
          },
          "status": {
            "$ref": "#/components/schemas/VulnerabilityStatus"
          },
          "cve": {
            "type": ["string", "null"]
          },
          "cvss": {
            "type": ["number", "null"]
          },
          "target": {
            "type": ["string", "null"],
            "description": "Affected URL, host, file, package, or other finding target when reported."
          },
          "endpoint": {
            "type": ["string", "null"],
            "description": "Affected HTTP endpoint or code location when reported."
          },
          "method": {
            "type": ["string", "null"],
            "description": "HTTP method when the finding applies to a request endpoint."
          },
          "created_at": {
            "type": "string",
            "format": "date-time"
          },
          "pr_review_id": {
            "type": "string",
            "format": "uuid",
            "description": "The review run that most recently reported this issue."
          },
          "provider": {
            "type": "string",
            "enum": ["github", "gitlab", "bitbucket"]
          },
          "repository_full_name": {
            "type": "string"
          },
          "pr_number": {
            "type": "integer"
          },
          "pr_title": {
            "type": ["string", "null"]
          },
          "pr_state": {
            "type": ["string", "null"],
            "enum": ["open", "merged", "closed", null],
            "description": "The lifecycle of the pull request itself. Null means the state is unknown for old review rows."
          }
        },
        "required": [
          "id",
          "title",
          "severity",
          "status",
          "cve",
          "cvss",
          "target",
          "endpoint",
          "method",
          "created_at",
          "pr_review_id",
          "provider",
          "repository_full_name",
          "pr_number",
          "pr_title",
          "pr_state"
        ]
      },
      "PrReviewImpactStats": {
        "type": "object",
        "description": "All-time PR review impact numbers for the organization. Counts cover distinct pull requests and distinct issues, not review runs.",
        "properties": {
          "prs_reviewed": {
            "type": "integer",
            "description": "Distinct pull requests with at least one finished review."
          },
          "issues_found": {
            "type": "integer",
            "description": "Distinct security issues that reviews caught. Dependency CVEs and retests are excluded."
          },
          "critical_high_found": {
            "type": "integer",
            "description": "Distinct critical and high severity issues."
          },
          "merges_blocked": {
            "type": "integer",
            "description": "Distinct pull requests that received a request_changes verdict."
          }
        },
        "required": [
          "prs_reviewed",
          "issues_found",
          "critical_high_found",
          "merges_blocked"
        ]
      },
      "PaginatedResponse_PrReviewCaughtFinding": {
        "type": "object",
        "properties": {
          "items": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/PrReviewCaughtFinding"
            }
          },
          "meta": {
            "$ref": "#/components/schemas/PaginationMeta"
          },
          "stats": {
            "$ref": "#/components/schemas/PrReviewImpactStats"
          }
        },
        "required": ["items", "meta"]
      },
      "PrReviewSettingsValues": {
        "type": "object",
        "description": "Stored per-organization automatic PR review configuration.",
        "properties": {
          "organization_id": { "type": "string" },
          "exclude_bots": {
            "type": "boolean",
            "description": "Skip PRs opened by bot authors."
          },
          "excluded_authors": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "maxItems": 500,
            "description": "Author logins to exclude from automatic review."
          },
          "reviewed_bots": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "maxItems": 200,
            "description": "Bot logins to review despite exclude_bots."
          },
          "review_on_push": {
            "type": "boolean",
            "description": "Re-review when new commits are pushed."
          },
          "allow_overage": {
            "type": "boolean",
            "description": "Permit reviews beyond the plan limit."
          },
          "overage_review_cap": {
            "type": ["integer", "null"],
            "minimum": 51,
            "description": "Maximum reviews when overage is allowed. A null value means no cap."
          },
          "block_on_findings": {
            "type": "boolean",
            "description": "When true (default), a review whose findings include a severity in blocking_severities submits a blocking review (GitHub REQUEST_CHANGES / failed status). When false, findings never block."
          },
          "blocking_severities": {
            "type": "array",
            "items": {
              "type": "string",
              "enum": ["critical", "high", "medium", "low"]
            },
            "maxItems": 4,
            "description": "Finding severities that trigger a blocking review when block_on_findings is enabled. Defaults to critical and high."
          },
          "approve_clean_prs": {
            "type": "boolean",
            "description": "When true, submit a GitHub approval on a clean PR instead of a silent commit-status-only pass."
          },
          "target_branches": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "maxItems": 100,
            "description": "Branch-name patterns (single `*` wildcard, case-insensitive) restricting automatic reviews to PRs whose base/target branch matches. Empty array reviews all branches."
          },
          "updated_by": {
            "type": ["string", "null"]
          },
          "updated_at": {
            "type": ["string", "null"],
            "format": "date-time"
          }
        },
        "required": [
          "organization_id",
          "exclude_bots",
          "excluded_authors",
          "reviewed_bots",
          "review_on_push",
          "target_branches",
          "allow_overage",
          "overage_review_cap",
          "block_on_findings",
          "blocking_severities",
          "approve_clean_prs",
          "updated_by",
          "updated_at"
        ]
      },
      "PrReviewSettings": {
        "allOf": [
          { "$ref": "#/components/schemas/PrReviewSettingsValues" },
          {
            "type": "object",
            "properties": { "tier": { "type": "string" } },
            "required": ["tier"]
          }
        ]
      },
      "UpdatePrReviewSettingsRequest": {
        "type": "object",
        "description": "Partial settings update. Supply at least one property; omitted settings keep their current values.",
        "additionalProperties": false,
        "minProperties": 1,
        "properties": {
          "exclude_bots": { "type": "boolean", "description": "Skip PRs opened by bot authors." },
          "excluded_authors": {
            "description": "Full replacement list of author logins to exclude from automatic review.",
            "type": "array",
            "items": { "type": "string" },
            "maxItems": 500
          },
          "reviewed_bots": {
            "description": "Full replacement list of bot logins to review even when exclude_bots is true.",
            "type": "array",
            "items": { "type": "string" },
            "maxItems": 200
          },
          "review_on_push": { "type": "boolean", "description": "Re-review when new commits are pushed." },
          "target_branches": {
            "description": "Branch-name patterns (single `*` wildcard, case-insensitive) that limit automatic reviews to matching base branches. An empty array reviews all branches.",
            "type": "array",
            "items": { "type": "string" },
            "maxItems": 100
          },
          "allow_overage": { "type": "boolean", "description": "Permit reviews beyond the plan limit." },
          "overage_review_cap": { "type": ["integer", "null"], "minimum": 51, "description": "Maximum reviews when overage is allowed. Send null for no cap." },
          "block_on_findings": { "type": "boolean", "description": "When true, findings with a severity in blocking_severities submit a blocking review. When false, findings never block." },
          "blocking_severities": {
            "description": "Finding severities that trigger a blocking review when block_on_findings is true.",
            "type": "array",
            "items": {
              "type": "string",
              "enum": ["critical", "high", "medium", "low"]
            },
            "maxItems": 4
          },
          "approve_clean_prs": { "type": "boolean", "description": "When true, submit a GitHub approval on a clean PR instead of only a passing commit status." }
        }
      },
      "UpdatePrReviewSettingsResponse": {
        "allOf": [
          { "$ref": "#/components/schemas/PrReviewSettingsValues" },
          {
            "type": "object",
            "properties": { "success": { "type": "boolean", "const": true } },
            "required": ["success"]
          }
        ]
      },
      "VulnerabilityHistoryEntry": {
        "type": "object",
        "description": "One lifecycle audit entry for a vulnerability. Nullable previous/new values represent baselines or cleared state.",
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "vulnerability_id": {
            "type": "string"
          },
          "previous_status": {
            "type": ["string", "null"]
          },
          "new_status": {
            "type": ["string", "null"]
          },
          "previous_severity": {
            "type": ["string", "null"],
            "enum": ["critical", "high", "medium", "low", null]
          },
          "new_severity": {
            "type": ["string", "null"],
            "enum": ["critical", "high", "medium", "low", null]
          },
          "previous_snoozed_until": {
            "type": ["string", "null"],
            "format": "date-time"
          },
          "new_snoozed_until": {
            "type": ["string", "null"],
            "format": "date-time"
          },
          "changed_by": {
            "type": "string"
          },
          "note": {
            "type": ["string", "null"]
          },
          "reason": {
            "type": ["string", "null"]
          },
          "created_at": {
            "type": "string",
            "format": "date-time"
          }
        },
        "required": [
          "id",
          "vulnerability_id",
          "previous_status",
          "new_status",
          "previous_severity",
          "new_severity",
          "previous_snoozed_until",
          "new_snoozed_until",
          "changed_by",
          "note",
          "reason",
          "created_at"
        ]
      },
      "SupplyChainOrgSummary": {
        "type": "object",
        "description": "Organization-wide supply-chain totals and one summary per repository visible to the caller.",
        "properties": {
          "totals": {
            "$ref": "#/components/schemas/SupplyChainOrgTotals"
          },
          "repositories": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/SupplyChainRepositorySummaryRow"
            }
          }
        },
        "required": ["totals", "repositories"]
      },
      "SupplyChainOrgTotals": {
        "type": "object",
        "properties": {
          "repositories": { "type": "integer", "minimum": 0 },
          "components": { "type": "integer", "minimum": 0 },
          "findings": { "type": "integer", "minimum": 0 },
          "open_issues": {
            "type": "integer",
            "minimum": 0,
            "description": "Open dependency findings across the visible repositories."
          },
          "malicious": { "type": "integer", "minimum": 0 },
          "suspicious": { "type": "integer", "minimum": 0 },
          "vulnerable": { "type": "integer", "minimum": 0 },
          "ecosystems": {
            "type": "object",
            "additionalProperties": { "type": "integer", "minimum": 0 }
          },
          "severities": {
            "type": "object",
            "additionalProperties": { "type": "integer", "minimum": 0 }
          }
        },
        "required": [
          "repositories",
          "components",
          "findings",
          "open_issues",
          "malicious",
          "suspicious",
          "vulnerable",
          "ecosystems",
          "severities"
        ]
      },
      "SupplyChainRepositorySummaryRow": {
        "type": "object",
        "properties": {
          "repository": {
            "$ref": "#/components/schemas/SupplyChainRepositoryIdentity"
          },
          "summary": {
            "$ref": "#/components/schemas/SupplyChainRepositorySummary"
          },
          "latest_supply_chain_scan": {
            "oneOf": [
              { "$ref": "#/components/schemas/SupplyChainScanReference" },
              { "type": "null" }
            ]
          }
        },
        "required": ["repository", "summary", "latest_supply_chain_scan"]
      },
      "SupplyChainRepositoryIdentity": {
        "type": "object",
        "properties": {
          "id": { "type": "string", "format": "uuid" },
          "organization_id": { "type": "string" },
          "full_name": { "type": "string" },
          "provider": { "type": "string", "enum": ["github", "gitlab"] },
          "installation_id": { "type": ["integer", "null"] },
          "supply_chain_enabled": { "type": "boolean" },
          "supply_chain_pr_checks_enabled": { "type": "boolean" },
          "supply_chain_policy_mode": {
            "type": "string",
            "enum": ["monitor", "comment", "block"]
          }
        },
        "required": [
          "id",
          "organization_id",
          "full_name",
          "provider",
          "installation_id",
          "supply_chain_enabled",
          "supply_chain_pr_checks_enabled",
          "supply_chain_policy_mode"
        ]
      },
      "SupplyChainRepositorySummary": {
        "type": "object",
        "properties": {
          "latest_snapshot": {
            "type": ["object", "null"],
            "additionalProperties": true
          },
          "latest_job": {
            "type": ["object", "null"],
            "additionalProperties": true
          },
          "component_count": { "type": "integer", "minimum": 0 },
          "finding_count": { "type": "integer", "minimum": 0 },
          "malicious_count": { "type": "integer", "minimum": 0 },
          "suspicious_count": { "type": "integer", "minimum": 0 },
          "vulnerable_count": { "type": "integer", "minimum": 0 },
          "ecosystem_counts": {
            "type": "object",
            "additionalProperties": { "type": "integer", "minimum": 0 }
          },
          "severity_counts": {
            "type": "object",
            "additionalProperties": { "type": "integer", "minimum": 0 }
          },
          "policy": {
            "$ref": "#/components/schemas/SupplyChainPolicySummary"
          }
        },
        "required": [
          "latest_snapshot",
          "latest_job",
          "component_count",
          "finding_count",
          "malicious_count",
          "suspicious_count",
          "vulnerable_count",
          "ecosystem_counts",
          "severity_counts",
          "policy"
        ]
      },
      "SupplyChainPolicySummary": {
        "type": "object",
        "properties": {
          "enabled": { "type": "boolean" },
          "pr_checks_enabled": { "type": "boolean" },
          "mode": {
            "type": "string",
            "enum": ["monitor", "comment", "block"]
          }
        },
        "required": ["enabled", "pr_checks_enabled", "mode"]
      },
      "SupplyChainScanReference": {
        "type": "object",
        "properties": {
          "id": { "type": "string", "format": "uuid" },
          "status": { "type": "string" },
          "created_at": { "type": "string", "format": "date-time" }
        },
        "required": ["id", "status", "created_at"]
      },
      "KnowledgeDocument": {
        "type": "object",
        "description": "An organization knowledge document.",
        "additionalProperties": true,
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "title": {
            "type": "string"
          },
          "source_type": {
            "type": "string"
          },
          "tags": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "created_at": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "CreateKnowledgeDocumentRequest": {
        "type": "object",
        "properties": {
          "title": {
            "description": "Short title of the document.",
            "type": "string",
            "maxLength": 200
          },
          "content": {
            "description": "Body of the document in plain text or Markdown. The agent reads it during scans.",
            "type": "string",
            "maxLength": 20000
          },
          "tags": {
            "description": "Labels that group related documents.",
            "type": "array",
            "items": {
              "type": "string",
              "maxLength": 60
            },
            "maxItems": 15
          },
          "metadata": {
            "description": "Free-form JSON object stored with the document.",
            "type": "object",
            "additionalProperties": true
          }
        },
        "required": ["title", "content"]
      },
      "UpdateKnowledgeDocumentRequest": {
        "type": "object",
        "properties": {
          "title": {
            "description": "New title of the document.",
            "type": "string",
            "maxLength": 200
          },
          "content": {
            "description": "New body of the document in plain text or Markdown.",
            "type": "string",
            "maxLength": 20000
          },
          "tags": {
            "description": "Full replacement list of labels for the document.",
            "type": "array",
            "items": {
              "type": "string",
              "maxLength": 60
            },
            "maxItems": 15
          },
          "metadata": {
            "description": "Full replacement JSON object stored with the document.",
            "type": "object",
            "additionalProperties": true
          }
        }
      },
      "KnowledgePolicy": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string"
          },
          "organization_id": {
            "type": "string"
          },
          "policy_key": {
            "type": "string"
          },
          "policy_value": {
            "type": "string"
          },
          "policy_type": {
            "type": "string"
          },
          "metadata": {
            "type": "object",
            "additionalProperties": true
          },
          "is_active": {
            "type": "boolean"
          },
          "created_at": {
            "type": ["string", "null"],
            "format": "date-time"
          },
          "updated_at": {
            "type": ["string", "null"],
            "format": "date-time"
          }
        },
        "required": [
          "id",
          "organization_id",
          "policy_key",
          "policy_value",
          "policy_type",
          "metadata",
          "is_active",
          "created_at",
          "updated_at"
        ]
      },
      "UpsertKnowledgePolicyRequest": {
        "type": "object",
        "properties": {
          "policy_key": {
            "description": "Unique key of the policy. Sending an existing key updates that policy.",
            "type": "string",
            "minLength": 1,
            "maxLength": 120
          },
          "policy_value": {
            "description": "Rule text the agent follows, for example `Never submit forms on the production checkout`.",
            "type": "string",
            "minLength": 1,
            "maxLength": 12000
          },
          "policy_type": {
            "description": "Category of the policy, for example `constraint` or `preference`.",
            "type": "string",
            "minLength": 1,
            "maxLength": 60,
            "default": "constraint"
          },
          "is_active": {
            "description": "When false, the policy is stored but the agent ignores it.",
            "type": "boolean",
            "default": true
          },
          "metadata": {
            "description": "Free-form JSON object stored with the policy.",
            "type": "object",
            "additionalProperties": true,
            "default": {}
          }
        },
        "required": ["policy_key", "policy_value"]
      },
      "KnowledgeSettings": {
        "type": "object",
        "description": "Organization knowledge configuration.",
        "additionalProperties": true,
        "properties": {
          "org_knowledge_enabled": {
            "type": "boolean",
            "description": "Whether organization knowledge is applied during scans and reviews."
          }
        }
      },
      "IntegrationsPayload": {
        "type": "object",
        "properties": {
          "integrations": {
            "type": "array",
            "items": {
              "type": "object",
              "additionalProperties": true
            }
          },
          "merge_accounts": {
            "type": "array",
            "items": {
              "type": "object",
              "additionalProperties": true
            }
          },
          "bitbucket_oauth_enabled": {
            "type": "boolean"
          }
        },
        "required": [
          "integrations",
          "merge_accounts",
          "bitbucket_oauth_enabled"
        ]
      },
      "ConnectScmRequest": {
        "type": "object",
        "description": "Connect a self-hosted or cloud SCM with a personal access token.",
        "properties": {
          "access_token": {
            "type": "string",
            "description": "Personal access token."
          },
          "instance_url": {
            "type": "string",
            "description": "Base URL for self-hosted instances (GitLab)."
          },
          "account_email": {
            "type": "string",
            "format": "email",
            "description": "Account email address (Bitbucket)."
          },
          "installation_id": {
            "type": "integer",
            "description": "Existing installation ID to update, if any."
          }
        },
        "required": ["access_token"]
      },
      "ValidateScmResponse": {
        "type": "object",
        "additionalProperties": true,
        "properties": {
          "valid": {
            "type": "boolean"
          }
        }
      },
      "UploadRequest": {
        "type": "object",
        "properties": {
          "file_name": {
            "description": "Name of the file to upload, including its extension.",
            "type": "string"
          },
          "file_size": {
            "description": "Size of the file in bytes.",
            "type": "integer"
          },
          "category": {
            "type": "string",
            "enum": ["repository", "documentation"],
            "description": "Optional. If it is not set, the category is inferred from the file. A .zip file is always categorized as repository even when documentation is requested."
          }
        },
        "required": ["file_name", "file_size"]
      },
      "UploadRequestResponse": {
        "type": "object",
        "properties": {
          "upload_id": {
            "type": "string",
            "format": "uuid"
          },
          "signed_url": {
            "type": "string",
            "description": "PUT the file bytes here."
          },
          "token": {
            "type": "string"
          },
          "storage_path": {
            "type": "string"
          },
          "file_type": {
            "type": "string"
          },
          "resumable": {
            "type": "object",
            "description": "Present only for large files that should use the resumable (TUS) protocol.",
            "properties": {
              "endpoint": {
                "type": "string"
              },
              "token": {
                "type": "string"
              },
              "bucket": {
                "type": "string"
              }
            },
            "required": ["endpoint", "token", "bucket"]
          }
        },
        "required": [
          "upload_id",
          "signed_url",
          "token",
          "storage_path",
          "file_type"
        ]
      },
      "UploadCompleteRequest": {
        "type": "object",
        "properties": {
          "upload_id": {
            "description": "ID returned by `requestUpload`.",
            "type": "string",
            "format": "uuid"
          }
        },
        "required": ["upload_id"]
      },
      "Upload": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "file_name": {
            "type": "string"
          },
          "file_type": {
            "type": "string"
          },
          "file_size": {
            "type": "integer"
          },
          "created_at": {
            "type": "string",
            "format": "date-time"
          }
        },
        "required": ["id", "file_name", "file_type", "file_size"]
      },
      "TestUserMfaMethod": {
        "type": "string",
        "enum": ["none", "totp", "email_otp", "magic_link"]
      },
      "TestUser": {
        "type": "object",
        "description": "A domain test account. Secrets are never returned — only boolean presence flags.",
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "organization_id": {
            "type": "string",
            "format": "uuid"
          },
          "domain_id": {
            "type": "string",
            "format": "uuid"
          },
          "scope_domain_ids": {
            "type": "array",
            "items": {
              "type": "string",
              "format": "uuid"
            },
            "description": "Domain ids this test user applies to. An empty array means it applies to every domain in the organization."
          },
          "label": {
            "type": "string"
          },
          "username": {
            "type": "string"
          },
          "notes": {
            "type": ["string", "null"]
          },
          "mfa_method": {
            "$ref": "#/components/schemas/TestUserMfaMethod"
          },
          "mfa_email": {
            "type": ["string", "null"]
          },
          "login_url": {
            "type": ["string", "null"]
          },
          "has_password": {
            "type": "boolean"
          },
          "has_totp_secret": {
            "type": "boolean"
          },
          "created_by": {
            "type": ["string", "null"]
          },
          "created_at": {
            "type": "string",
            "format": "date-time"
          },
          "updated_at": {
            "type": "string",
            "format": "date-time"
          }
        },
        "required": [
          "id",
          "label",
          "username",
          "mfa_method",
          "has_password",
          "has_totp_secret"
        ]
      },
      "TestUserAuthCheck": {
        "type": "object",
        "description": "Outcome of a pre-scan login verification run for a saved test user.",
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "test_user_id": {
            "type": ["string", "null"],
            "format": "uuid"
          },
          "status": {
            "type": "string",
            "enum": ["pending", "running", "succeeded", "failed"]
          },
          "failure_code": {
            "type": ["string", "null"],
            "enum": [
              "invalid_credentials",
              "login_page_not_found",
              "mfa_required_not_configured",
              "mfa_code_unavailable",
              "account_locked",
              "target_unreachable",
              "bot_protection",
              "launch_failed",
              "other",
              null
            ],
            "description": "Category of the failure when `status` is `failed`."
          },
          "detail": {
            "type": ["string", "null"],
            "description": "Human-readable explanation of the outcome. Never contains credentials or email contents."
          },
          "created_at": {
            "type": "string",
            "format": "date-time"
          },
          "started_at": {
            "type": ["string", "null"],
            "format": "date-time"
          },
          "finished_at": {
            "type": ["string", "null"],
            "format": "date-time"
          }
        },
        "required": ["id", "status", "created_at"]
      },
      "TestUserListResponse": {
        "type": "object",
        "properties": {
          "items": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/TestUser"
            }
          },
          "agentmail_configured": {
            "type": "boolean",
            "description": "Whether Strix-managed inboxes can be provisioned for email-based MFA."
          },
          "auth_checks": {
            "type": "object",
            "description": "Latest login verification per test user, keyed by test user id. Absent keys have never been verified.",
            "additionalProperties": {
              "$ref": "#/components/schemas/TestUserAuthCheck"
            }
          }
        },
        "required": ["items", "agentmail_configured"]
      },
      "CreateTestUserRequest": {
        "type": "object",
        "properties": {
          "label": {
            "type": "string",
            "description": "Display label for the test user."
          },
          "username": {
            "type": "string",
            "description": "Login username/email."
          },
          "password": {
            "type": "string",
            "description": "Stored encrypted. Never returned."
          },
          "notes": {
            "description": "Free-text hints for the agent, for example which role the account has.",
            "type": "string"
          },
          "login_url": {
            "description": "URL of the login page where the agent signs in with this account.",
            "type": "string"
          },
          "mfa_method": {
            "description": "Second factor the account uses. `none` for password only.",
            "$ref": "#/components/schemas/TestUserMfaMethod"
          },
          "totp_secret": {
            "type": "string",
            "description": "Required when mfa_method=totp. Stored encrypted."
          },
          "mfa_email": {
            "type": "string",
            "description": "Required for email_otp/magic_link. Must be a Strix-managed inbox in the caller's org pod (see provision-inbox)."
          },
          "scope_domain_ids": {
            "type": "array",
            "items": {
              "type": "string",
              "format": "uuid"
            },
            "description": "Domain ids this test user applies to. Empty array = every domain in the organization (requires unrestricted access). Defaults to the route's domain."
          }
        },
        "required": ["label", "username"]
      },
      "UpdateTestUserRequest": {
        "type": "object",
        "description": "Partial update. Only provided fields are changed.",
        "properties": {
          "label": {
            "description": "New display label for the test user.",
            "type": "string"
          },
          "username": {
            "description": "New login username or email.",
            "type": "string"
          },
          "password": {
            "description": "New password. Stored encrypted and never returned.",
            "type": "string"
          },
          "notes": {
            "description": "New free-text hints for the agent.",
            "type": "string"
          },
          "login_url": {
            "description": "New URL of the login page.",
            "type": "string"
          },
          "mfa_method": {
            "description": "New second factor the account uses. `none` for password only.",
            "$ref": "#/components/schemas/TestUserMfaMethod"
          },
          "totp_secret": {
            "description": "New TOTP secret. Required when mfa_method is `totp`. Stored encrypted and never returned.",
            "type": "string"
          },
          "mfa_email": {
            "description": "New Strix-managed inbox for `email_otp` or `magic_link` MFA.",
            "type": "string"
          },
          "scope_domain_ids": {
            "type": "array",
            "items": {
              "type": "string",
              "format": "uuid"
            },
            "description": "Domain ids this test user applies to. Empty array = every domain in the organization (requires unrestricted access)."
          }
        }
      },
      "ProvisionInboxRequest": {
        "type": "object",
        "properties": {
          "label": {
            "type": "string",
            "description": "Optional label for the generated inbox."
          }
        }
      },
      "InboxMessage": {
        "type": "object",
        "additionalProperties": true,
        "properties": {
          "id": {
            "type": "string"
          },
          "from": {
            "type": "string"
          },
          "subject": {
            "type": "string"
          },
          "received_at": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "InboxMessageList": {
        "type": "object",
        "additionalProperties": true,
        "properties": {
          "messages": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/InboxMessage"
            }
          }
        }
      },
      "ScopeEntry": {
        "type": "object",
        "properties": {
          "kind": {
            "type": "string",
            "enum": ["domain", "subdomain", "wildcard"]
          },
          "value": {
            "type": "string",
            "description": "e.g. \"app.acme.com\" or \"*.acme.com\"."
          },
          "source": {
            "type": "string",
            "enum": ["seed", "discovery", "manual"]
          }
        },
        "required": ["kind", "value", "source"]
      },
      "NotificationSettings": {
        "type": "object",
        "description": "Organization notification settings. SLA reminders send a daily digest of vulnerabilities approaching or past their remediation deadline (critical/high 30 days, medium 60, low 90).",
        "properties": {
          "sla_reminders_enabled": {
            "type": "boolean",
            "description": "Whether SLA deadline reminders are enabled. Defaults to false."
          },
          "sla_reminder_email": {
            "type": "boolean",
            "description": "Deliver the digest to organization members by email."
          },
          "sla_reminder_slack": {
            "type": "boolean",
            "description": "Post the digest to the organization's default Slack channel."
          },
          "sla_warning_days": {
            "type": "integer",
            "minimum": 1,
            "maximum": 30,
            "description": "Days before the deadline to start reminding. Defaults to 7."
          }
        },
        "required": [
          "sla_reminders_enabled",
          "sla_reminder_email",
          "sla_reminder_slack",
          "sla_warning_days"
        ]
      },
      "UpdateNotificationSettingsRequest": {
        "type": "object",
        "description": "Partial update of organization notification settings. At least one field is required.",
        "properties": {
          "sla_reminders_enabled": {
            "type": "boolean",
            "description": "Whether SLA deadline reminders are enabled. Defaults to false."
          },
          "sla_reminder_email": {
            "type": "boolean",
            "description": "Deliver the digest to organization members by email."
          },
          "sla_reminder_slack": {
            "type": "boolean",
            "description": "Post the digest to the organization's default Slack channel."
          },
          "sla_warning_days": {
            "type": "integer",
            "minimum": 1,
            "maximum": 30,
            "description": "Days before the deadline to start reminding. Defaults to 7."
          }
        }
      },
      "ScanCreditPaywallResponse": {
        "type": "object",
        "description": "Returned with status 402 when the workspace has no scan credits for the request. No scan starts and no credits are consumed.",
        "properties": {
          "detail": {
            "type": "string",
            "description": "Human-readable explanation with the short recovery instruction. When `plan_trial` is present, the text also offers the Cloud plan trial."
          },
          "requiredTier": {
            "type": "string"
          },
          "code": {
            "type": "string",
            "enum": ["scan_credit_limit_reached"]
          },
          "hint": {
            "type": "string",
            "description": "Short recovery instruction: how to buy credits, then retry."
          },
          "topup_url": {
            "type": "string",
            "format": "uri",
            "description": "The dashboard billing page where a user can buy credits."
          },
          "topup_options": {
            "type": "array",
            "description": "Ways to add credits, in the order a headless caller should try them.",
            "items": {
              "type": "object",
              "properties": {
                "method": { "type": "string", "enum": ["GET", "POST"] },
                "path": {
                  "type": "string",
                  "description": "The API path, relative to the API root."
                },
                "cli": {
                  "type": "string",
                  "description": "The matching Strix CLI command."
                },
                "description": { "type": "string" }
              },
              "required": ["method", "path", "cli", "description"]
            }
          },
          "plan_trial": {
            "type": "object",
            "description": "The Cloud plan trial. Present only when the workspace has not subscribed before and can still start the trial. The plan includes PR security reviews and does not include scan credits.",
            "properties": {
              "plan": {
                "type": "string",
                "enum": ["strix_cloud"],
                "description": "The `product` value for `POST /api/v1/billing/checkout`."
              },
              "trial_days": {
                "type": "integer",
                "description": "Maximum length of the free trial in days."
              },
              "includes": {
                "type": "string",
                "description": "What the plan includes."
              },
              "method": { "type": "string", "enum": ["POST"] },
              "path": {
                "type": "string",
                "description": "The API path, relative to the API root."
              },
              "cli": {
                "type": "string",
                "description": "The matching Strix CLI command."
              },
              "url": {
                "type": "string",
                "format": "uri",
                "description": "The dashboard billing page where a user can start the trial."
              },
              "description": { "type": "string" }
            },
            "required": ["plan", "trial_days", "includes", "method", "path", "cli", "url", "description"]
          },
          "required_credits": {
            "type": "integer",
            "description": "Total credits the request needs."
          },
          "available_credits": {
            "type": "integer",
            "description": "Credits currently in the workspace wallet."
          }
        },
        "required": ["detail", "code", "hint", "topup_url", "topup_options"]
      },
      "TierLimitErrorResponse": {
        "type": "object",
        "properties": {
          "detail": {
            "type": "string"
          },
          "requiredTier": {
            "type": "string"
          },
          "code": {
            "type": "string"
          }
        },
        "required": ["detail"]
      },
      "CliDeviceAuthorization": {
        "type": "object",
        "properties": {
          "device_code": {
            "type": "string",
            "description": "Code the CLI uses to poll for tokens. Never show this code to the user."
          },
          "user_code": {
            "type": "string",
            "description": "Short code the user confirms in the browser."
          },
          "verification_uri": {
            "type": "string",
            "description": "URL where the user enters the user code."
          },
          "verification_uri_complete": {
            "type": "string",
            "description": "URL with the user code prefilled, suitable for opening in a browser."
          },
          "expires_in": {
            "type": "integer",
            "description": "Seconds until the device authorization expires."
          },
          "interval": {
            "type": "integer",
            "description": "Minimum seconds to wait between polls."
          }
        },
        "required": [
          "device_code",
          "user_code",
          "verification_uri",
          "verification_uri_complete",
          "expires_in",
          "interval"
        ]
      },
      "CliScopeProfile": {
        "type": "string",
        "enum": ["minimal", "recommended", "full", "custom"],
        "description": "Named CLI authority preference. Minimal grants scans and billing:read. Recommended adds every scope that everyday `strix cloud` commands use: vulnerabilities, dependencies, supply chain, schedules, assets, knowledge, PR reviews, connectors, chat, uploads, integrations, analytics, license, webhooks:read, audit:read, organizations:read, organizations:write, and billing:write. Full means the session's approved ceiling after login and adds account administration (members, invitations, tokens, webhooks:write, LLM, test users). Custom requires an explicit scopes array. The member's role caps every profile."
      },
      "CliLoginResult": {
        "type": "object",
        "properties": {
          "api_token": {
            "type": "string",
            "description": "Raw personal API token secret. Only returned at sign-in time."
          },
          "organization_id": {
            "type": "string"
          },
          "organization_name": {
            "type": "string"
          },
          "email": {
            "type": "string"
          },
          "expires_at": {
            "type": "string",
            "format": "date-time",
            "description": "Expiry of the API token."
          },
          "is_new_user": {
            "type": "boolean",
            "description": "True when this sign-in created the account."
          },
          "scopes": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ApiV1Scope"
            },
            "description": "Scopes granted to the minted token."
          },
          "scope_ceiling": {
            "type": "array",
            "items": { "$ref": "#/components/schemas/ApiV1Scope" },
            "description": "Maximum authority approved for this session at login."
          },
          "requested_scopes": {
            "type": "array",
            "items": { "$ref": "#/components/schemas/ApiV1Scope" }
          },
          "scope_profile": {
            "$ref": "#/components/schemas/CliScopeProfile"
          },
          "token_id": { "type": "string", "format": "uuid" },
          "credential_source": { "type": "string", "enum": ["api", "cli"] },
          "device_name": { "type": ["string", "null"] },
          "onboarding": {
            "$ref": "#/components/schemas/CliOnboardingState",
            "description": "Setup state of the workspace that received the token. Omitted when the server cannot read the live workspace state. The token is still valid in that case."
          },
          "next_steps_hint": {
            "type": "string",
            "description": "One short paragraph with the first commands to run after sign-in. When the workspace still has its default name, the text names the rename command for a session with organizations:write, and tells other sessions to ask a workspace admin or to sign in again with the full profile. When `onboarding.github_install_url` is present, the text tells the person to open the link. When the session also has integrations:write, the text names the command that creates a new link. When the workspace can still start the Cloud plan trial and the new session can call the billing checkout operation, the text also offers the trial. The session must have the billing:write scope and no asset scopes."
          },
          "next_steps": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/CliNextStep"
            },
            "description": "Suggested first actions, in order. Each item names the CLI command and the matching API operation. Setup steps come first: name the workspace when the session has organizations:write and the workspace still has its default name, and connect GitHub when the session has integrations:write, no asset scopes, and `onboarding.github_install_url` is present. A deployment without the GitHub App never gets the GitHub step. When the workspace can still start the Cloud plan trial and the new session can call the billing checkout operation, the last item starts the trial. The session must have the billing:write scope and no asset scopes."
          },
          "dashboard_url": {
            "type": "string",
            "format": "uri",
            "description": "URL of the Strix dashboard."
          }
        },
        "required": [
          "api_token",
          "organization_id",
          "organization_name",
          "email",
          "expires_at",
          "is_new_user",
          "scopes",
          "scope_ceiling",
          "requested_scopes",
          "scope_profile",
          "token_id",
          "credential_source"
        ]
      },
      "CliNextStep": {
        "type": "object",
        "properties": {
          "action": {
            "type": "string",
            "description": "What the step does, for example `List your workspaces`."
          },
          "cli": {
            "type": "string",
            "description": "The Strix CLI command for this step."
          },
          "method": {
            "type": "string",
            "enum": ["GET", "POST", "PATCH"]
          },
          "path": {
            "type": "string",
            "description": "The API path for this step, relative to the API root."
          }
        },
        "required": ["action", "cli", "method", "path"]
      },
      "CliOnboardingState": {
        "type": "object",
        "description": "Setup state of the workspace that received the token. The server computes it from live data on every sign-in, so it is correct for new and returning users. When the server cannot read the live state, the sign-in response omits this object instead of reporting unverified values.",
        "properties": {
          "workspace_named": {
            "type": "boolean",
            "description": "False while the workspace still has the name the server generated at sign-up, for example `Alex's Workspace`. The server records the origin of the name, so a later profile change does not alter this value. Rename the workspace with PATCH /organization."
          },
          "repositories_connected": {
            "type": "boolean",
            "description": "True when at least one repository has an active installation in the workspace. Repositories from a disconnected installation do not count."
          },
          "domains_added": {
            "type": "boolean",
            "description": "True when at least one domain is added to the workspace."
          },
          "github_install_url": {
            "type": "string",
            "format": "uri",
            "description": "Link to install the Strix GitHub App on the workspace. Present for an admin session without asset scopes while no repository is connected. A person opens the link in a browser. When the browser has no dashboard session, the dashboard asks the person to sign in with the same account and returns to the installation. The new browser session is bound to this workspace. The link expires after 10 minutes. POST /integrations/github/install-url creates a new one. Absent when this deployment has no GitHub App."
          }
        },
        "required": ["workspace_named", "repositories_connected", "domains_added"]
      },
      "CliLoginBrowserHint": {
        "type": "object",
        "description": "Returned for a browser GET on a POST-only CLI sign-in route. No sign-in action happens.",
        "properties": {
          "detail": {
            "type": "string",
            "description": "Explanation of the endpoint and what the user must do instead."
          },
          "error": {
            "type": "string",
            "enum": ["method_not_allowed"]
          },
          "method": {
            "type": "string",
            "enum": ["POST"],
            "description": "The HTTP method that this endpoint accepts."
          },
          "path": {
            "type": "string",
            "description": "The API path of this endpoint, relative to the API root."
          },
          "cli": {
            "type": "string",
            "description": "The Strix CLI command that starts a sign-in."
          },
          "install_url": {
            "type": "string",
            "format": "uri",
            "description": "Where to install the Strix CLI."
          },
          "docs_url": {
            "type": "string",
            "format": "uri",
            "description": "The CLI documentation."
          }
        },
        "required": ["detail", "error", "method", "path", "cli", "install_url", "docs_url"]
      },
      "CliLoginSelection": {
        "type": "object",
        "description": "Selection step of an interactive CLI sign-in. Show the workspaces and the scope catalog to the user, then finish with POST /cli/login/complete.",
        "properties": {
          "selection_required": {
            "type": "boolean",
            "description": "Always true for this response shape."
          },
          "selection_token": {
            "type": "string",
            "description": "Short-lived token for POST /cli/login/complete."
          },
          "expires_in": {
            "type": "integer",
            "description": "Lifetime of the selection token in seconds."
          },
          "is_new_user": {
            "type": "boolean",
            "description": "True when this sign-in created the account. The CLI can then offer the first-time setup prompts."
          },
          "organizations": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/CliWorkspaceOption"
            },
            "description": "Workspaces the user is a member of."
          },
          "scopes": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/CliScopeOption"
            },
            "description": "Catalog of all scopes with descriptions, defaults, and role requirements."
          }
        },
        "required": [
          "selection_required",
          "selection_token",
          "expires_in",
          "is_new_user",
          "organizations",
          "scopes"
        ]
      },
      "CliWorkspaceOption": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string"
          },
          "name": {
            "type": "string"
          },
          "role": {
            "type": "string",
            "enum": ["admin", "analyst", "viewer"],
            "description": "The user's role in this workspace. The role limits which scopes the token can receive."
          },
          "has_default_name": {
            "type": "boolean",
            "description": "True when the user is an admin and the workspace still has the generated default name, for example `Alex's Workspace`. Offer a `workspace_name` on POST /cli/login/complete."
          }
        },
        "required": ["id", "name", "role", "has_default_name"]
      },
      "CliScopeOption": {
        "type": "object",
        "properties": {
          "scope": {
            "$ref": "#/components/schemas/ApiV1Scope"
          },
          "description": {
            "type": "string",
            "description": "Plain-language description of what the scope allows."
          },
          "minimum": {
            "type": "boolean",
            "description": "True when the server always includes this scope."
          },
          "default": {
            "type": "boolean",
            "description": "True when this scope is part of the default set."
          },
          "min_role": {
            "type": "string",
            "enum": ["admin", "analyst", "viewer"],
            "description": "Lowest role that can receive this scope."
          }
        },
        "required": ["scope", "description", "minimum", "default", "min_role"]
      },
      "CreditBalance": {
        "type": "object",
        "properties": {
          "balance": {
            "type": "integer",
            "description": "Current top-up credit balance for the organization."
          },
          "price_per_credit_cents": {
            "type": "integer",
            "description": "Price of one credit in USD cents."
          }
        },
        "required": ["balance", "price_per_credit_cents"]
      },
      "TopupRequest": {
        "type": "object",
        "properties": {
          "credits": {
            "type": "integer",
            "minimum": 1,
            "maximum": 10000,
            "description": "Number of credits to purchase."
          }
        },
        "required": ["credits"]
      },
      "TopupResult": {
        "type": "object",
        "properties": {
          "credits_granted": {
            "type": "integer",
            "description": "Credits granted by this payment. Zero when the payment was already processed."
          },
          "duplicate": {
            "type": "boolean",
            "description": "True when this payment reference was already granted."
          },
          "reference": {
            "type": "string",
            "description": "Payment reference from the payment receipt."
          },
          "balance": {
            "type": "integer",
            "description": "Credit balance after the grant."
          }
        },
        "required": ["credits_granted", "duplicate", "reference", "balance"]
      },
      "AutoTopupSettings": {
        "type": "object",
        "properties": {
          "enabled": {
            "type": "boolean",
            "description": "True when automatic top-up is active."
          },
          "topup_credits": {
            "type": "integer",
            "minimum": 1,
            "maximum": 10000,
            "description": "Credits purchased for each automatic top-up."
          },
          "monthly_cap_credits": {
            "type": ["integer", "null"],
            "description": "Maximum automatically purchased credits per calendar month. Null removes the cap."
          },
          "used_this_month": {
            "type": "integer",
            "description": "Credits already purchased automatically this month."
          }
        },
        "required": [
          "enabled",
          "topup_credits",
          "monthly_cap_credits",
          "used_this_month"
        ]
      },
      "Workspace": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string"
          },
          "name": {
            "type": "string"
          },
          "role": {
            "type": "string",
            "enum": ["admin", "analyst", "viewer"]
          },
          "current": {
            "type": "boolean",
            "description": "True for the workspace of the token that made the request."
          }
        },
        "required": ["id", "name", "role"]
      },
      "WorkspaceList": {
        "type": "object",
        "properties": {
          "workspaces": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Workspace"
            }
          }
        },
        "required": ["workspaces"]
      },
      "CreateWorkspaceRequest": {
        "type": "object",
        "properties": {
          "name": {
            "type": "string",
            "maxLength": 100,
            "description": "The workspace name."
          }
        },
        "required": ["name"]
      },
      "CreateWorkspaceTokenRequest": {
        "type": "object",
        "properties": {
          "scopes": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ApiV1Scope"
            },
            "description": "Custom requested scopes. The server adds the minimum baseline and rejects any scope outside the immutable login ceiling."
          },
          "scope_profile": {
            "$ref": "#/components/schemas/CliScopeProfile"
          },
          "client_instance_id": {
            "type": "string",
            "minLength": 8,
            "maxLength": 128,
            "description": "Optional device identity used only to upgrade a legacy CLI credential. Must be sent with device_name."
          },
          "device_name": {
            "description": "Human-readable name of the device that holds the credential, for example `Alex MacBook`.",
            "type": "string",
            "minLength": 1,
            "maxLength": 80
          }
        }
      },
      "WorkspaceToken": {
        "type": "object",
        "properties": {
          "api_token": {
            "type": "string"
          },
          "organization_id": {
            "type": "string"
          },
          "organization_name": {
            "type": "string"
          },
          "email": {
            "type": "string"
          },
          "expires_at": {
            "type": ["string", "null"],
            "format": "date-time"
          },
          "scopes": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ApiV1Scope"
            }
          },
          "scope_ceiling": {
            "type": "array",
            "items": { "$ref": "#/components/schemas/ApiV1Scope" }
          },
          "requested_scopes": {
            "type": "array",
            "items": { "$ref": "#/components/schemas/ApiV1Scope" }
          },
          "scope_profile": {
            "$ref": "#/components/schemas/CliScopeProfile"
          },
          "token_id": { "type": "string", "format": "uuid" },
          "credential_source": { "type": "string", "enum": ["api", "cli"] },
          "device_name": { "type": ["string", "null"] }
        },
        "required": [
          "api_token",
          "organization_id",
          "organization_name",
          "scopes",
          "scope_ceiling",
          "requested_scopes",
          "scope_profile",
          "token_id",
          "credential_source"
        ]
      },
      "CliSession": {
        "type": "object",
        "properties": {
          "token_id": { "type": "string", "format": "uuid" },
          "credential_source": { "type": "string", "enum": ["api", "cli"] },
          "organization_id": { "type": "string" },
          "email": { "type": ["string", "null"] },
          "device_name": { "type": ["string", "null"] },
          "client_instance_id": { "type": ["string", "null"] },
          "scopes": {
            "type": "array",
            "items": { "$ref": "#/components/schemas/ApiV1Scope" }
          },
          "scope_ceiling": {
            "type": "array",
            "items": { "$ref": "#/components/schemas/ApiV1Scope" }
          },
          "requested_scopes": {
            "type": "array",
            "items": { "$ref": "#/components/schemas/ApiV1Scope" }
          },
          "scope_profile": { "$ref": "#/components/schemas/CliScopeProfile" }
        },
        "required": [
          "token_id",
          "credential_source",
          "organization_id",
          "scopes",
          "scope_ceiling",
          "requested_scopes",
          "scope_profile"
        ]
      },
      "CreateCheckoutRequest": {
        "type": "object",
        "properties": {
          "product": {
            "type": "string",
            "enum": ["strix_top_up", "strix_cloud", "strix_startup"],
            "description": "The product to buy."
          },
          "success_url": {
            "type": "string",
            "description": "The page to open after the payment. The server accepts only a same-origin address."
          }
        },
        "required": ["product"]
      },
      "CheckoutLink": {
        "type": "object",
        "properties": {
          "checkout_url": {
            "type": "string"
          }
        },
        "required": ["checkout_url"]
      },
      "PortalLink": {
        "type": "object",
        "properties": {
          "portal_url": {
            "type": "string"
          }
        },
        "required": ["portal_url"]
      },
      "InstallationLink": {
        "type": "object",
        "properties": {
          "url": {
            "type": "string"
          }
        },
        "required": ["url"]
      }
    },
    "headers": {
      "IdempotencyKeyResponse": {
        "description": "Echoes the caller's Idempotency-Key on keyed operation responses.",
        "schema": {
          "type": "string"
        }
      },
      "IdempotencyReplayed": {
        "description": "`true` when this response was replayed from the durable receipt; `false` on the original keyed response.",
        "schema": {
          "type": "string",
          "enum": ["true", "false"]
        }
      },
      "IdempotencyRetryAfter": {
        "description": "Minimum seconds to wait before retrying the exact request with the same Idempotency-Key.",
        "schema": {
          "type": "integer",
          "minimum": 1
        }
      }
    },
    "responses": {
      "IdempotencyBadRequest": {
        "description": "Bad request, including a malformed Idempotency-Key.",
        "headers": {
          "Idempotency-Key": {
            "$ref": "#/components/headers/IdempotencyKeyResponse"
          },
          "Idempotency-Replayed": {
            "$ref": "#/components/headers/IdempotencyReplayed"
          }
        },
        "content": {
          "application/json": {
            "schema": {
              "oneOf": [
                {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                {
                  "$ref": "#/components/schemas/InvalidIdempotencyKeyError"
                }
              ]
            }
          }
        }
      },
      "IdempotencyConflictOrInProgress": {
        "description": "The key is bound to a different request (terminal), the exact matching request is still in progress (retry-safe), or an accepted launch can no longer reconstruct its original endpoint resource (terminal; do not launch again).",
        "headers": {
          "Idempotency-Key": {
            "$ref": "#/components/headers/IdempotencyKeyResponse"
          },
          "Idempotency-Replayed": {
            "$ref": "#/components/headers/IdempotencyReplayed"
          },
          "Retry-After": {
            "$ref": "#/components/headers/IdempotencyRetryAfter"
          }
        },
        "content": {
          "application/json": {
            "schema": {
              "oneOf": [
                {
                  "$ref": "#/components/schemas/IdempotencyKeyConflictError"
                },
                {
                  "$ref": "#/components/schemas/IdempotencyRequestInProgressError"
                },
                {
                  "$ref": "#/components/schemas/IdempotencyAcceptedResponseUnavailableError"
                }
              ]
            }
          }
        }
      },
      "IdempotencyOutcomeUnknown": {
        "description": "The outcome is still being reconciled. Retry the exact request with the same key after Retry-After; do not generate a new key.",
        "headers": {
          "Idempotency-Key": {
            "$ref": "#/components/headers/IdempotencyKeyResponse"
          },
          "Idempotency-Replayed": {
            "$ref": "#/components/headers/IdempotencyReplayed"
          },
          "Retry-After": {
            "$ref": "#/components/headers/IdempotencyRetryAfter"
          }
        },
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/IdempotencyOutcomeUnknownError"
            }
          }
        }
      },
      "IdempotencyInternalOrAbandoned": {
        "description": "Internal server error, or a reconciled attempt that did not reach durable acceptance. An `idempotency_attempt_abandoned` response is terminal for this key; use a new key only for a deliberate new launch.",
        "headers": {
          "Idempotency-Key": {
            "$ref": "#/components/headers/IdempotencyKeyResponse"
          },
          "Idempotency-Replayed": {
            "$ref": "#/components/headers/IdempotencyReplayed"
          }
        },
        "content": {
          "application/json": {
            "schema": {
              "oneOf": [
                {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                {
                  "$ref": "#/components/schemas/IdempotencyAttemptAbandonedError"
                }
              ]
            }
          }
        }
      },
      "BadRequest": {
        "description": "Bad request.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/ErrorResponse"
            }
          }
        }
      },
      "Unauthorized": {
        "description": "Missing or invalid API token.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/ErrorResponse"
            }
          }
        }
      },
      "Forbidden": {
        "description": "Insufficient permissions or missing scope. A missing scope returns the `insufficient_scope` code, the `required_scope` field, and a `hint` with the command or page that grants the scope, so a client can request the correct scope and retry.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/ErrorResponse"
            }
          }
        }
      },
      "TierLimitError": {
        "description": "Plan or credit limit reached.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/TierLimitErrorResponse"
            }
          }
        }
      },
      "NotFound": {
        "description": "Resource not found.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/ErrorResponse"
            }
          }
        }
      },
      "ValidationError": {
        "description": "Request failed validation (e.g. malformed value or unsupported enum).",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/ErrorResponse"
            }
          }
        }
      },
      "PaymentRequired": {
        "description": "Out of credits. The body explains how to buy credits with the API, the CLI, or the dashboard, then retry the request.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/ScanCreditPaywallResponse"
            }
          }
        }
      },
      "InternalError": {
        "description": "Internal server error.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/ErrorResponse"
            }
          }
        }
      },
      "Conflict": {
        "description": "Conflict.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/ErrorResponse"
            }
          }
        }
      },
      "BadGateway": {
        "description": "Bad gateway.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/ErrorResponse"
            }
          }
        }
      },
      "ServiceUnavailable": {
        "description": "Service unavailable.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/ErrorResponse"
            }
          }
        }
      }
    }
  },
  "tags": [
    {
      "name": "Scans",
      "description": "Launch, monitor, and manage security scans."
    },
    {
      "name": "Vulnerabilities",
      "description": "View and triage discovered vulnerabilities."
    },
    {
      "name": "Assets",
      "description": "Domains and repositories registered for scanning."
    },
    {
      "name": "Schedules",
      "description": "Recurring scan schedules (Pro plan)."
    },
    {
      "name": "Tokens",
      "description": "Manage API tokens for authentication."
    },
    {
      "name": "Webhooks",
      "description": "Configure webhook subscriptions for real-time event notifications."
    },
    {
      "name": "Organization",
      "description": "Workspace configuration for the authenticated organization."
    },
    {
      "name": "Members",
      "description": "Manage organization members and roles."
    },
    {
      "name": "Invitations",
      "description": "List and revoke organization invitations."
    },
    {
      "name": "PR Reviews",
      "description": "Automated security review of pull requests."
    },
    {
      "name": "Connectors",
      "description": "Network connectors for scanning internal/private targets."
    },
    {
      "name": "Knowledge",
      "description": "Organization knowledge base: documents, policies, and repo profiles that steer the agent."
    },
    {
      "name": "Uploads",
      "description": "Upload source/code/documentation archives for whitebox scans."
    },
    {
      "name": "Integrations",
      "description": "Third-party integrations (GitLab, Bitbucket, ticketing)."
    },
    {
      "name": "Chat",
      "description": "Conversational agent sessions."
    },
    {
      "name": "Analytics",
      "description": "Aggregate dashboard analytics."
    },
    {
      "name": "Test Users",
      "description": "Per-domain test accounts (with optional MFA) the agent authenticates as during scans."
    },
    {
      "name": "License",
      "description": "Self-hosted license state, entitlements, and aggregate usage."
    },
    {
      "name": "Supply Chain",
      "description": "SBOM inventory, supply-chain findings, scans, and policy for connected repositories."
    },
    {
      "name": "CLI",
      "description": "Device authorization endpoints that let the Strix CLI and coding agents sign in and receive an API token."
    },
    {
      "name": "Billing",
      "description": "Credit balance, agent-payable top-ups, and automatic top-up settings."
    },
    {
      "name": "Workspaces",
      "description": "List, create, and switch workspaces."
    }
  ]
}
