{
  "openapi": "3.0.3",
  "info": {
    "title": "Panoptic Scans API",
    "description": "Complete API for Panoptic Scans - a comprehensive security scanning platform.\n\n## Authentication\nAll endpoints (except `/api/token`) require Bearer token authentication.\n\n1. Obtain your API key from your account settings\n2. Exchange it for a JWT token using `/api/token`\n3. Include the token in the Authorization header: `Bearer {token}`\n4. Tokens can be refreshed using `/api/refresh`\n\n## Rate Limits\nAPI requests are subject to rate limiting based on your subscription tier.\n\n## Pagination\nList endpoints support pagination with `per_page` parameter (max 100).\n",
    "version": "1.2.0",
    "contact": {
      "name": "Panoptic Scans Support",
      "url": "https://panopticscans.com"
    },
    "license": {
      "name": "Proprietary"
    }
  },
  "servers": [
    {
      "url": "https://panopticscans.com",
      "description": "Production server"
    },
    {
      "url": "http://localhost:8000",
      "description": "Local development server"
    }
  ],
  "tags": [
    {
      "name": "Authentication",
      "description": "Authentication and token management"
    },
    {
      "name": "Scans",
      "description": "Security scan management"
    },
    {
      "name": "Vulnerabilities",
      "description": "Vulnerability tracking and management"
    },
    {
      "name": "Targets",
      "description": "Target asset management"
    },
    {
      "name": "Webhooks",
      "description": "Webhook management for scan event notifications. Configure HTTPS endpoints to receive callbacks when scans complete or fail. Supports custom URLs, Slack, Discord, and Microsoft Teams. All deliveries are signed with HMAC-SHA256 using a per-webhook secret."
    }
  ],
  "paths": {
    "/api/token": {
      "post": {
        "tags": [
          "Authentication"
        ],
        "summary": "Get API Token",
        "description": "Exchange your API key for a JWT authentication token",
        "operationId": "getToken",
        "parameters": [
          {
            "name": "key",
            "in": "query",
            "required": true,
            "description": "Your API key from account settings",
            "schema": {
              "type": "string"
            },
            "example": "YOUR_API_KEY_HERE"
          }
        ],
        "responses": {
          "200": {
            "description": "Token generated successfully",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "token": {
                      "type": "string",
                      "description": "JWT authentication token"
                    },
                    "expires_in": {
                      "type": "integer",
                      "description": "Token expiration time in seconds"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Invalid API key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/api/refresh": {
      "post": {
        "tags": [
          "Authentication"
        ],
        "summary": "Refresh Token",
        "description": "Refresh your authentication token",
        "operationId": "refreshToken",
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "Token refreshed successfully",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "token": {
                      "type": "string"
                    },
                    "expires_in": {
                      "type": "integer"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/UnauthorizedError"
          }
        }
      }
    },
    "/api/user": {
      "get": {
        "tags": [
          "Authentication"
        ],
        "summary": "Get Authenticated User",
        "description": "Get current user information",
        "operationId": "getUser",
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "User information retrieved",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/User"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/UnauthorizedError"
          }
        }
      }
    },
    "/api/scans": {
      "get": {
        "tags": [
          "Scans"
        ],
        "summary": "List All Scans",
        "description": "Retrieve all scans for the authenticated user",
        "operationId": "listScans",
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "List of scans",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/Scan"
                      }
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/UnauthorizedError"
          }
        }
      }
    },
    "/api/new-scan": {
      "post": {
        "tags": [
          "Scans"
        ],
        "summary": "Create New Scan",
        "description": "Create a new security scan. Target format varies by scan type:\n- **Nmap/OpenVAS/Nuclei**: IP addresses, hostnames, or CIDR ranges (without http/https)\n- **ZAP**: Full URLs with http:// or https://\n\n**Authenticated ZAP Scanning**: For ZAP scans, you can enable authenticated scanning by setting `zap_authenticated` to true and providing a Selenium login script via `zap_login_script` (base64-encoded Python file). This allows ZAP to scan behind login pages by replaying a Selenium-based authentication flow before spidering and scanning the target.\n\n**Internal Network Scanning** (Pro/Admin only): For OpenVAS scans, set `scan_frequency` to `Unmanaged` to create an internal network scan. This creates a scan placeholder that you run locally on your own VM using the `openvas_local_scan.sh` script. The script handles uploading results back to the platform automatically.\n\n**Attack Narrative** (Premium/Pro/Admin only): Set `include_attack_narrative` to true to include an AI-generated attack narrative in your scan reports.\n",
        "operationId": "createScan",
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "scan_name",
                  "scan_type",
                  "scan_frequency",
                  "scan_time_zone",
                  "scan_email",
                  "scan_target"
                ],
                "properties": {
                  "scan_name": {
                    "type": "string",
                    "maxLength": 255,
                    "description": "Name for the scan",
                    "example": "API Test Scan"
                  },
                  "scan_type": {
                    "type": "string",
                    "enum": [
                      "Nmap",
                      "OpenVas",
                      "ZAP",
                      "Nuclei"
                    ],
                    "description": "Type of security scan",
                    "example": "Nmap"
                  },
                  "scan_frequency": {
                    "type": "string",
                    "enum": [
                      "One-time",
                      "Daily",
                      "Weekly",
                      "Monthly",
                      "Quarterly",
                      "Yearly",
                      "Unmanaged"
                    ],
                    "description": "Scan frequency. Use 'Unmanaged' for internal network scans run locally via the openvas_local_scan.sh script (Pro/Admin only).",
                    "example": "One-time"
                  },
                  "scan_start_date": {
                    "type": "string",
                    "maxLength": 25,
                    "description": "Start date (for scheduled scans)",
                    "example": "September 23, 2025"
                  },
                  "scan_start_time": {
                    "type": "string",
                    "maxLength": 10,
                    "description": "Start time (for scheduled scans)",
                    "example": "8:45 PM"
                  },
                  "scan_time_zone": {
                    "type": "string",
                    "maxLength": 35,
                    "description": "Timezone for scheduled scan",
                    "example": "America/New_York"
                  },
                  "scan_email": {
                    "type": "string",
                    "format": "email",
                    "maxLength": 100,
                    "description": "Email address for scan results",
                    "example": "user@example.com"
                  },
                  "scan_target": {
                    "type": "string",
                    "description": "Target(s) - format depends on scan_type. Multiple targets separated by commas, spaces, or newlines",
                    "example": "scanme.nmap.org"
                  },
                  "zap_authenticated": {
                    "type": "boolean",
                    "default": false,
                    "description": "Enable authenticated scanning for ZAP scans. When true, a login script must be provided.",
                    "example": false
                  },
                  "zap_login_script": {
                    "type": "string",
                    "format": "byte",
                    "description": "Base64-encoded Python Selenium login script for authenticated ZAP scanning. Required when zap_authenticated is true.",
                    "example": "IyBFeGFtcGxlIGxvZ2luIHNjcmlwdApmcm9tIHNlbGVuaXVtIGltcG9ydCB3ZWJkcml2ZXI="
                  },
                  "include_attack_narrative": {
                    "type": "boolean",
                    "default": false,
                    "description": "Include AI-generated attack narrative in scan reports. Only available for Premium, Pro, and Admin users.",
                    "example": true
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Scan created successfully",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "message": {
                      "type": "string",
                      "description": "Scan UUID",
                      "example": "e510ab1c-1dec-41a5-86c9-9499220912ac"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/UnauthorizedError"
          },
          "422": {
            "description": "Validation error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ValidationError"
                }
              }
            }
          }
        }
      }
    },
    "/api/scans/{uuid}": {
      "put": {
        "tags": [
          "Scans"
        ],
        "summary": "Update Scan",
        "description": "Update scan properties. You can update the scan name, and for ZAP scans, you can also enable/disable authenticated scanning and update the login script.\n\n**Authenticated ZAP Scanning**: For ZAP scans, set `zap_authenticated` to true/false and optionally provide a new `zap_login_script` (base64-encoded Python file). Use `remove_login_script: true` to remove an existing script.\n\n**Attack Narrative** (Premium/Pro/Admin only): Set `include_attack_narrative` to true/false to enable or disable the AI-generated attack narrative in your scan reports.",
        "operationId": "updateScan",
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/ScanUUID"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "scan_name": {
                    "type": "string",
                    "maxLength": 255,
                    "description": "New name for the scan",
                    "example": "Updated Scan Name"
                  },
                  "zap_authenticated": {
                    "type": "boolean",
                    "description": "Enable or disable authenticated scanning for ZAP scans",
                    "example": true
                  },
                  "zap_login_script": {
                    "type": "string",
                    "format": "byte",
                    "description": "Base64-encoded Python Selenium login script for authenticated ZAP scanning",
                    "example": "IyBFeGFtcGxlIGxvZ2luIHNjcmlwdApmcm9tIHNlbGVuaXVtIGltcG9ydCB3ZWJkcml2ZXI="
                  },
                  "remove_login_script": {
                    "type": "boolean",
                    "description": "Set to true to remove the existing login script and disable authenticated scanning",
                    "example": false
                  },
                  "include_attack_narrative": {
                    "type": "boolean",
                    "description": "Enable or disable AI-generated attack narrative in scan reports. Only available for Premium, Pro, and Admin users.",
                    "example": true
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Scan updated successfully",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "message": {
                      "type": "string",
                      "example": "Successfully updated scan."
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/UnauthorizedError"
          },
          "404": {
            "$ref": "#/components/responses/NotFoundError"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      },
      "delete": {
        "tags": [
          "Scans"
        ],
        "summary": "Delete Scan",
        "description": "Delete a scan and all associated data",
        "operationId": "deleteScan",
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/ScanUUID"
          }
        ],
        "responses": {
          "200": {
            "description": "Scan deleted successfully",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "message": {
                      "type": "string",
                      "example": "Successfully deleted scan."
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/UnauthorizedError"
          },
          "404": {
            "$ref": "#/components/responses/NotFoundError"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/api/scans/{uuid}/runs": {
      "get": {
        "tags": [
          "Scans"
        ],
        "summary": "List Scan Runs",
        "description": "Get all available runs for a scan with available report formats",
        "operationId": "getScanRuns",
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/ScanUUID"
          }
        ],
        "responses": {
          "200": {
            "description": "List of scan runs",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "scan": {
                      "type": "object",
                      "properties": {
                        "uuid": {
                          "type": "string"
                        },
                        "name": {
                          "type": "string"
                        },
                        "type": {
                          "type": "string"
                        },
                        "current_progress": {
                          "type": "string"
                        },
                        "run_count": {
                          "type": "integer"
                        },
                        "total_runs": {
                          "type": "integer"
                        }
                      }
                    },
                    "runs": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "run_index": {
                            "type": "integer"
                          },
                          "run_folder": {
                            "type": "integer"
                          },
                          "status": {
                            "type": "string",
                            "enum": [
                              "current",
                              "completed"
                            ]
                          },
                          "completed_at": {
                            "type": "string",
                            "format": "date-time"
                          },
                          "scan_progress": {
                            "type": "string"
                          },
                          "available_formats": {
                            "type": "array",
                            "items": {
                              "type": "string",
                              "enum": [
                                "pdf",
                                "csv",
                                "html",
                                "txt",
                                "xml"
                              ]
                            }
                          }
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/UnauthorizedError"
          },
          "404": {
            "$ref": "#/components/responses/NotFoundError"
          }
        }
      }
    },
    "/api/scans/pdf/{uuid}": {
      "get": {
        "tags": [
          "Scans"
        ],
        "summary": "Get PDF Report",
        "description": "Download scan results as PDF (optionally for a specific run)",
        "operationId": "getPDF",
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/ScanUUID"
          },
          {
            "$ref": "#/components/parameters/RunIndex"
          }
        ],
        "responses": {
          "200": {
            "description": "PDF file",
            "content": {
              "application/pdf": {
                "schema": {
                  "type": "string",
                  "format": "binary"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/UnauthorizedError"
          },
          "404": {
            "$ref": "#/components/responses/NotFoundError"
          }
        }
      }
    },
    "/api/scans/csv/{uuid}": {
      "get": {
        "tags": [
          "Scans"
        ],
        "summary": "Get CSV Report",
        "description": "Download scan results as CSV (optionally for a specific run)",
        "operationId": "getCSV",
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/ScanUUID"
          },
          {
            "$ref": "#/components/parameters/RunIndex"
          }
        ],
        "responses": {
          "200": {
            "description": "CSV file",
            "content": {
              "text/csv": {
                "schema": {
                  "type": "string",
                  "format": "binary"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/UnauthorizedError"
          },
          "404": {
            "$ref": "#/components/responses/NotFoundError"
          }
        }
      }
    },
    "/api/scans/html/{uuid}": {
      "get": {
        "tags": [
          "Scans"
        ],
        "summary": "Get HTML Report",
        "description": "Download scan results as HTML (optionally for a specific run)",
        "operationId": "getHTML",
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/ScanUUID"
          },
          {
            "$ref": "#/components/parameters/RunIndex"
          }
        ],
        "responses": {
          "200": {
            "description": "HTML file",
            "content": {
              "text/html": {
                "schema": {
                  "type": "string"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/UnauthorizedError"
          },
          "404": {
            "$ref": "#/components/responses/NotFoundError"
          }
        }
      }
    },
    "/api/scans/txt/{uuid}": {
      "get": {
        "tags": [
          "Scans"
        ],
        "summary": "Get TXT Report",
        "description": "Download scan results as plain text (optionally for a specific run)",
        "operationId": "getTXT",
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/ScanUUID"
          },
          {
            "$ref": "#/components/parameters/RunIndex"
          }
        ],
        "responses": {
          "200": {
            "description": "Text file",
            "content": {
              "text/plain": {
                "schema": {
                  "type": "string"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/UnauthorizedError"
          },
          "404": {
            "$ref": "#/components/responses/NotFoundError"
          }
        }
      }
    },
    "/api/scans/xml/{uuid}": {
      "get": {
        "tags": [
          "Scans"
        ],
        "summary": "Get XML Report",
        "description": "Download scan results as XML (optionally for a specific run)",
        "operationId": "getXML",
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/ScanUUID"
          },
          {
            "$ref": "#/components/parameters/RunIndex"
          }
        ],
        "responses": {
          "200": {
            "description": "XML file",
            "content": {
              "application/xml": {
                "schema": {
                  "type": "string"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/UnauthorizedError"
          },
          "404": {
            "$ref": "#/components/responses/NotFoundError"
          }
        }
      }
    },
    "/api/vulnerabilities": {
      "get": {
        "tags": [
          "Vulnerabilities"
        ],
        "summary": "List All Vulnerabilities",
        "description": "Get all vulnerabilities with optional filtering, sorting, and pagination",
        "operationId": "listVulnerabilities",
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "parameters": [
          {
            "name": "severity",
            "in": "query",
            "description": "Filter by severity level",
            "schema": {
              "type": "string",
              "enum": [
                "Critical",
                "High",
                "Medium",
                "Low",
                "Informational"
              ]
            },
            "example": "Critical"
          },
          {
            "name": "status",
            "in": "query",
            "description": "Filter by status",
            "schema": {
              "type": "string",
              "enum": [
                "Unresolved",
                "Accepted",
                "False Positive"
              ]
            },
            "example": "Unresolved"
          },
          {
            "name": "target",
            "in": "query",
            "description": "Filter by target hostname or IP",
            "schema": {
              "type": "string"
            },
            "example": "example.com"
          },
          {
            "name": "search",
            "in": "query",
            "description": "Search in vulnerability name, hostname, IP, or scan name",
            "schema": {
              "type": "string"
            },
            "example": "SQL"
          },
          {
            "name": "sort",
            "in": "query",
            "description": "Field to sort by",
            "schema": {
              "type": "string",
              "enum": [
                "name",
                "threat",
                "cvss_base",
                "hostname",
                "host_ip",
                "scan_type",
                "status",
                "created_at"
              ],
              "default": "cvss_base"
            },
            "example": "cvss_base"
          },
          {
            "name": "direction",
            "in": "query",
            "description": "Sort direction",
            "schema": {
              "type": "string",
              "enum": [
                "asc",
                "desc"
              ],
              "default": "desc"
            },
            "example": "desc"
          },
          {
            "name": "per_page",
            "in": "query",
            "description": "Items per page (max 100)",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 100,
              "default": 10
            },
            "example": 25
          }
        ],
        "responses": {
          "200": {
            "description": "List of vulnerabilities",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/Vulnerability"
                      }
                    },
                    "meta": {
                      "$ref": "#/components/schemas/PaginationMeta"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/UnauthorizedError"
          }
        }
      }
    },
    "/api/vulnerabilities/{id}": {
      "get": {
        "tags": [
          "Vulnerabilities"
        ],
        "summary": "Get Vulnerability Details",
        "description": "Get detailed information about a specific vulnerability",
        "operationId": "getVulnerability",
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "Vulnerability ID",
            "schema": {
              "type": "integer"
            },
            "example": 123
          }
        ],
        "responses": {
          "200": {
            "description": "Vulnerability details",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "$ref": "#/components/schemas/Vulnerability"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/UnauthorizedError"
          },
          "404": {
            "$ref": "#/components/responses/NotFoundError"
          }
        }
      }
    },
    "/api/vulnerabilities/{id}/accept": {
      "post": {
        "tags": [
          "Vulnerabilities"
        ],
        "summary": "Accept Vulnerability",
        "description": "Mark a vulnerability as accepted (risk acknowledged)",
        "operationId": "acceptVulnerability",
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "Vulnerability ID",
            "schema": {
              "type": "integer"
            },
            "example": 123
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Vulnerability marked as accepted",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "message": {
                      "type": "string",
                      "example": "Vulnerability marked as accepted"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/UnauthorizedError"
          },
          "404": {
            "$ref": "#/components/responses/NotFoundError"
          }
        }
      }
    },
    "/api/vulnerabilities/{id}/false-positive": {
      "post": {
        "tags": [
          "Vulnerabilities"
        ],
        "summary": "Mark as False Positive",
        "description": "Mark a vulnerability as a false positive",
        "operationId": "falsePositiveVulnerability",
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "Vulnerability ID",
            "schema": {
              "type": "integer"
            },
            "example": 123
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Vulnerability marked as false positive",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "message": {
                      "type": "string",
                      "example": "Vulnerability marked as false positive"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/UnauthorizedError"
          },
          "404": {
            "$ref": "#/components/responses/NotFoundError"
          }
        }
      }
    },
    "/api/vulnerabilities/{id}/undo": {
      "post": {
        "tags": [
          "Vulnerabilities"
        ],
        "summary": "Reset Vulnerability Status",
        "description": "Reset vulnerability status back to unresolved",
        "operationId": "undoVulnerability",
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "Vulnerability ID",
            "schema": {
              "type": "integer"
            },
            "example": 123
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Vulnerability status reset to unresolved",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "message": {
                      "type": "string",
                      "example": "Vulnerability status reset to unresolved"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/UnauthorizedError"
          },
          "404": {
            "$ref": "#/components/responses/NotFoundError"
          }
        }
      }
    },
    "/api/vulnerabilities/export": {
      "get": {
        "tags": [
          "Vulnerabilities"
        ],
        "summary": "Export Vulnerabilities CSV",
        "description": "Export vulnerabilities to CSV with optional filtering",
        "operationId": "exportVulnerabilities",
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "parameters": [
          {
            "name": "severity",
            "in": "query",
            "description": "Filter by severity level",
            "schema": {
              "type": "string",
              "enum": [
                "Critical",
                "High",
                "Medium",
                "Low",
                "Informational"
              ]
            },
            "example": "High"
          },
          {
            "name": "status",
            "in": "query",
            "description": "Filter by status",
            "schema": {
              "type": "string",
              "enum": [
                "Unresolved",
                "Accepted",
                "False Positive"
              ]
            },
            "example": "Unresolved"
          },
          {
            "name": "target",
            "in": "query",
            "description": "Filter by target hostname or IP",
            "schema": {
              "type": "string"
            },
            "example": "example.com"
          },
          {
            "name": "search",
            "in": "query",
            "description": "Search term",
            "schema": {
              "type": "string"
            },
            "example": "XSS"
          }
        ],
        "responses": {
          "200": {
            "description": "CSV file with vulnerabilities",
            "content": {
              "text/csv": {
                "schema": {
                  "type": "string",
                  "format": "binary"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/UnauthorizedError"
          }
        }
      }
    },
    "/api/targets": {
      "get": {
        "tags": [
          "Targets"
        ],
        "summary": "List All Targets",
        "description": "Get all targets with optional filtering, sorting, and pagination",
        "operationId": "listTargets",
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "parameters": [
          {
            "name": "search",
            "in": "query",
            "description": "Search in target, description, or type",
            "schema": {
              "type": "string"
            },
            "example": "example.com"
          },
          {
            "name": "type",
            "in": "query",
            "description": "Filter by target type",
            "schema": {
              "type": "string",
              "enum": [
                "Domain",
                "Ip"
              ]
            },
            "example": "Domain"
          },
          {
            "name": "status",
            "in": "query",
            "description": "Filter by status",
            "schema": {
              "type": "string",
              "enum": [
                "Active",
                "Inactive",
                "Unknown"
              ]
            },
            "example": "Active"
          },
          {
            "name": "sort",
            "in": "query",
            "description": "Field to sort by",
            "schema": {
              "type": "string",
              "enum": [
                "target",
                "type",
                "status",
                "last_scan",
                "created_at",
                "vulnerabilities"
              ],
              "default": "last_scan"
            },
            "example": "last_scan"
          },
          {
            "name": "direction",
            "in": "query",
            "description": "Sort direction",
            "schema": {
              "type": "string",
              "enum": [
                "asc",
                "desc"
              ],
              "default": "desc"
            },
            "example": "desc"
          },
          {
            "name": "per_page",
            "in": "query",
            "description": "Items per page (max 100)",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 100,
              "default": 10
            },
            "example": 25
          }
        ],
        "responses": {
          "200": {
            "description": "List of targets",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/Target"
                      }
                    },
                    "meta": {
                      "$ref": "#/components/schemas/PaginationMeta"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/UnauthorizedError"
          }
        }
      }
    },
    "/api/targets/{id}": {
      "get": {
        "tags": [
          "Targets"
        ],
        "summary": "Get Target Details",
        "description": "Get detailed information about a specific target",
        "operationId": "getTarget",
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "Target ID",
            "schema": {
              "type": "integer"
            },
            "example": 456
          }
        ],
        "responses": {
          "200": {
            "description": "Target details",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "$ref": "#/components/schemas/Target"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/UnauthorizedError"
          },
          "404": {
            "$ref": "#/components/responses/NotFoundError"
          }
        }
      },
      "delete": {
        "tags": [
          "Targets"
        ],
        "summary": "Delete Target",
        "description": "Delete a target and all associated vulnerabilities",
        "operationId": "deleteTarget",
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "Target ID",
            "schema": {
              "type": "integer"
            },
            "example": 456
          }
        ],
        "responses": {
          "200": {
            "description": "Target deleted successfully",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "message": {
                      "type": "string",
                      "example": "Target example.com has been deleted successfully. 5 associated vulnerabilities were also removed."
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/UnauthorizedError"
          },
          "404": {
            "$ref": "#/components/responses/NotFoundError"
          }
        }
      }
    },
    "/api/targets/{id}/vulnerabilities": {
      "get": {
        "tags": [
          "Targets"
        ],
        "summary": "Get Target Vulnerabilities",
        "description": "Get all vulnerabilities for a specific target with pagination",
        "operationId": "getTargetVulnerabilities",
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "Target ID",
            "schema": {
              "type": "integer"
            },
            "example": 456
          },
          {
            "name": "sort",
            "in": "query",
            "description": "Field to sort by",
            "schema": {
              "type": "string",
              "enum": [
                "name",
                "threat",
                "cvss_base",
                "scan_type",
                "created_at"
              ],
              "default": "cvss_base"
            },
            "example": "cvss_base"
          },
          {
            "name": "direction",
            "in": "query",
            "description": "Sort direction",
            "schema": {
              "type": "string",
              "enum": [
                "asc",
                "desc"
              ],
              "default": "desc"
            },
            "example": "desc"
          },
          {
            "name": "per_page",
            "in": "query",
            "description": "Items per page (max 100)",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 100,
              "default": 10
            },
            "example": 25
          }
        ],
        "responses": {
          "200": {
            "description": "List of vulnerabilities for the target",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/Vulnerability"
                      }
                    },
                    "target": {
                      "$ref": "#/components/schemas/Target"
                    },
                    "meta": {
                      "$ref": "#/components/schemas/PaginationMeta"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/UnauthorizedError"
          },
          "404": {
            "$ref": "#/components/responses/NotFoundError"
          }
        }
      }
    },
    "/api/webhooks": {
      "get": {
        "tags": ["Webhooks"],
        "summary": "List Webhooks",
        "description": "Retrieve all webhooks for the authenticated user, including their secrets.",
        "operationId": "listWebhooks",
        "security": [{ "bearerAuth": [] }],
        "responses": {
          "200": {
            "description": "List of webhooks",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "type": "array",
                      "items": { "$ref": "#/components/schemas/Webhook" }
                    }
                  }
                }
              }
            }
          },
          "401": { "$ref": "#/components/responses/UnauthorizedError" }
        }
      },
      "post": {
        "tags": ["Webhooks"],
        "summary": "Create Webhook",
        "description": "Create a new webhook endpoint. A signing secret is automatically generated and returned in the response. Maximum 10 webhooks per user.\n\n**Supported events:** `scan.completed`, `scan.failed`\n\n**URL requirement:** Must be an HTTPS URL. Slack, Discord, and Microsoft Teams incoming webhook URLs are automatically detected and payloads are formatted accordingly.",
        "operationId": "createWebhook",
        "security": [{ "bearerAuth": [] }],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": ["url", "events"],
                "properties": {
                  "url": {
                    "type": "string",
                    "format": "uri",
                    "description": "HTTPS endpoint URL to receive webhook events",
                    "example": "https://example.com/webhooks/panoptic"
                  },
                  "events": {
                    "type": "array",
                    "items": {
                      "type": "string",
                      "enum": ["scan.completed", "scan.failed"]
                    },
                    "minItems": 1,
                    "description": "Events to subscribe to",
                    "example": ["scan.completed", "scan.failed"]
                  },
                  "description": {
                    "type": "string",
                    "maxLength": 255,
                    "nullable": true,
                    "description": "Optional description for this webhook",
                    "example": "Production alerting endpoint"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Webhook created successfully",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "message": {
                      "type": "string",
                      "example": "Webhook created successfully."
                    },
                    "data": { "$ref": "#/components/schemas/Webhook" }
                  }
                }
              }
            }
          },
          "401": { "$ref": "#/components/responses/UnauthorizedError" },
          "422": {
            "description": "Validation error or webhook limit reached",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/ValidationError" }
              }
            }
          }
        }
      }
    },
    "/api/webhooks/{id}": {
      "put": {
        "tags": ["Webhooks"],
        "summary": "Update Webhook",
        "description": "Update an existing webhook. All fields are optional — only provided fields are changed. Set `rotate_secret` to true to generate a new signing secret.",
        "operationId": "updateWebhook",
        "security": [{ "bearerAuth": [] }],
        "parameters": [{ "$ref": "#/components/parameters/WebhookId" }],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "url": {
                    "type": "string",
                    "format": "uri",
                    "description": "New HTTPS endpoint URL",
                    "example": "https://example.com/webhooks/panoptic-v2"
                  },
                  "events": {
                    "type": "array",
                    "items": {
                      "type": "string",
                      "enum": ["scan.completed", "scan.failed"]
                    },
                    "minItems": 1,
                    "description": "Events to subscribe to",
                    "example": ["scan.completed"]
                  },
                  "description": {
                    "type": "string",
                    "maxLength": 255,
                    "nullable": true,
                    "description": "Updated description"
                  },
                  "is_active": {
                    "type": "boolean",
                    "description": "Enable or disable the webhook",
                    "example": true
                  },
                  "rotate_secret": {
                    "type": "boolean",
                    "description": "Set to true to generate a new signing secret",
                    "example": false
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Webhook updated successfully",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "message": {
                      "type": "string",
                      "example": "Webhook updated successfully."
                    },
                    "data": { "$ref": "#/components/schemas/Webhook" }
                  }
                }
              }
            }
          },
          "401": { "$ref": "#/components/responses/UnauthorizedError" },
          "403": {
            "description": "Webhook does not belong to the authenticated user",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/Error" }
              }
            }
          },
          "404": { "$ref": "#/components/responses/NotFoundError" },
          "422": {
            "description": "Validation error",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/ValidationError" }
              }
            }
          }
        }
      },
      "delete": {
        "tags": ["Webhooks"],
        "summary": "Delete Webhook",
        "description": "Permanently delete a webhook and all its delivery history.",
        "operationId": "deleteWebhook",
        "security": [{ "bearerAuth": [] }],
        "parameters": [{ "$ref": "#/components/parameters/WebhookId" }],
        "responses": {
          "200": {
            "description": "Webhook deleted successfully",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "message": {
                      "type": "string",
                      "example": "Webhook deleted successfully."
                    }
                  }
                }
              }
            }
          },
          "401": { "$ref": "#/components/responses/UnauthorizedError" },
          "403": {
            "description": "Webhook does not belong to the authenticated user",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/Error" }
              }
            }
          },
          "404": { "$ref": "#/components/responses/NotFoundError" }
        }
      }
    },
    "/api/webhooks/{id}/test": {
      "post": {
        "tags": ["Webhooks"],
        "summary": "Test Webhook",
        "description": "Send a test `ping` event to the webhook endpoint with sample scan data. Use this to verify that your endpoint is reachable and correctly processing payloads before relying on it for real notifications.",
        "operationId": "testWebhook",
        "security": [{ "bearerAuth": [] }],
        "parameters": [{ "$ref": "#/components/parameters/WebhookId" }],
        "responses": {
          "200": {
            "description": "Test webhook dispatched",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "message": {
                      "type": "string",
                      "example": "Test webhook dispatched. Check your endpoint for the ping event."
                    }
                  }
                }
              }
            }
          },
          "401": { "$ref": "#/components/responses/UnauthorizedError" },
          "403": {
            "description": "Webhook does not belong to the authenticated user",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/Error" }
              }
            }
          },
          "404": { "$ref": "#/components/responses/NotFoundError" }
        }
      }
    },
    "/api/webhooks/{id}/deliveries": {
      "get": {
        "tags": ["Webhooks"],
        "summary": "List Webhook Deliveries",
        "description": "Get the most recent delivery attempts for a webhook (up to 50). Each delivery includes the event type, payload sent, HTTP response code, response body, and retry information.",
        "operationId": "listWebhookDeliveries",
        "security": [{ "bearerAuth": [] }],
        "parameters": [{ "$ref": "#/components/parameters/WebhookId" }],
        "responses": {
          "200": {
            "description": "List of deliveries",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "type": "array",
                      "items": { "$ref": "#/components/schemas/WebhookDelivery" }
                    }
                  }
                }
              }
            }
          },
          "401": { "$ref": "#/components/responses/UnauthorizedError" },
          "403": {
            "description": "Webhook does not belong to the authenticated user",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/Error" }
              }
            }
          },
          "404": { "$ref": "#/components/responses/NotFoundError" }
        }
      }
    }
  },
  "components": {
    "securitySchemes": {
      "bearerAuth": {
        "type": "http",
        "scheme": "bearer",
        "bearerFormat": "JWT",
        "description": "JWT token obtained from /api/token endpoint"
      }
    },
    "parameters": {
      "ScanUUID": {
        "name": "uuid",
        "in": "path",
        "required": true,
        "description": "Scan UUID",
        "schema": {
          "type": "string",
          "format": "uuid"
        },
        "example": "e510ab1c-1dec-41a5-86c9-9499220912ac"
      },
      "WebhookId": {
        "name": "id",
        "in": "path",
        "required": true,
        "description": "Webhook ID",
        "schema": {
          "type": "integer"
        },
        "example": 1
      },
      "RunIndex": {
        "name": "run_index",
        "in": "query",
        "required": false,
        "description": "Specific run index to retrieve (omit for latest run)",
        "schema": {
          "type": "integer",
          "minimum": 0
        },
        "example": 0
      }
    },
    "schemas": {
      "User": {
        "type": "object",
        "properties": {
          "id": {
            "type": "integer"
          },
          "name": {
            "type": "string"
          },
          "email": {
            "type": "string",
            "format": "email"
          },
          "role": {
            "type": "object",
            "properties": {
              "name": {
                "type": "string",
                "enum": [
                  "trial",
                  "basic",
                  "premium",
                  "pro",
                  "admin"
                ]
              }
            }
          }
        }
      },
      "Scan": {
        "type": "object",
        "properties": {
          "id": {
            "type": "integer"
          },
          "uuid": {
            "type": "string",
            "format": "uuid"
          },
          "user_id": {
            "type": "integer"
          },
          "scan_name": {
            "type": "string"
          },
          "scan_type": {
            "type": "string",
            "enum": [
              "Nmap",
              "OpenVas",
              "ZAP",
              "Nuclei"
            ]
          },
          "scan_target": {
            "type": "string"
          },
          "zap_authenticated": {
            "type": "boolean",
            "description": "Whether authenticated scanning is enabled (ZAP scans only)"
          },
          "zap_login_script": {
            "type": "string",
            "nullable": true,
            "description": "S3 path to the Selenium login script (ZAP scans only)"
          },
          "include_attack_narrative": {
            "type": "boolean",
            "description": "Whether AI-generated attack narrative is enabled (Premium, Pro, and Admin users only)"
          },
          "scan_frequency": {
            "type": "string",
            "enum": [
              "One-time",
              "Daily",
              "Weekly",
              "Monthly",
              "Quarterly",
              "Yearly",
              "Unmanaged"
            ]
          },
          "scan_progress": {
            "type": "string"
          },
          "run_count": {
            "type": "integer"
          },
          "created_at": {
            "type": "string",
            "format": "date-time"
          },
          "updated_at": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "Vulnerability": {
        "type": "object",
        "properties": {
          "id": {
            "type": "integer"
          },
          "user_id": {
            "type": "integer"
          },
          "name": {
            "type": "string",
            "description": "Vulnerability name"
          },
          "threat": {
            "type": "string",
            "enum": [
              "Critical",
              "High",
              "Medium",
              "Low",
              "Informational"
            ],
            "description": "Severity level"
          },
          "cvss_base": {
            "type": "number",
            "format": "float",
            "minimum": 0,
            "maximum": 10,
            "description": "CVSS base score"
          },
          "cvss_vector": {
            "type": "string",
            "description": "CVSS scoring vector"
          },
          "hostname": {
            "type": "string",
            "nullable": true,
            "description": "Target hostname"
          },
          "host_ip": {
            "type": "string",
            "nullable": true,
            "description": "Target IP address"
          },
          "port": {
            "type": "string",
            "nullable": true,
            "description": "Affected port"
          },
          "description": {
            "type": "string",
            "description": "Vulnerability description"
          },
          "solution": {
            "type": "string",
            "description": "Recommended solution"
          },
          "impact": {
            "type": "string",
            "nullable": true,
            "description": "Potential impact"
          },
          "evidence": {
            "type": "string",
            "nullable": true,
            "description": "Evidence of vulnerability"
          },
          "references": {
            "type": "string",
            "nullable": true,
            "description": "External references"
          },
          "scan_name": {
            "type": "string",
            "description": "Name of scan that found this vulnerability"
          },
          "scan_type": {
            "type": "string",
            "enum": [
              "Nmap",
              "OpenVas",
              "ZAP",
              "Nuclei"
            ],
            "description": "Type of scan"
          },
          "status": {
            "type": "string",
            "enum": [
              "Unresolved",
              "Accepted",
              "False Positive"
            ],
            "description": "Current status"
          },
          "status_updated_at": {
            "type": "string",
            "format": "date-time",
            "nullable": true,
            "description": "When status was last updated"
          },
          "created_at": {
            "type": "string",
            "format": "date-time"
          },
          "updated_at": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "Target": {
        "type": "object",
        "properties": {
          "id": {
            "type": "integer"
          },
          "user_id": {
            "type": "integer"
          },
          "target": {
            "type": "string",
            "description": "Original target string"
          },
          "normalized_target": {
            "type": "string",
            "description": "Normalized target for comparison"
          },
          "type": {
            "type": "string",
            "enum": [
              "Domain",
              "Ip"
            ],
            "description": "Target type"
          },
          "description": {
            "type": "string",
            "description": "Target description"
          },
          "status": {
            "type": "string",
            "enum": [
              "Active",
              "Inactive",
              "Unknown"
            ],
            "description": "Target status"
          },
          "last_scan": {
            "type": "string",
            "format": "date-time",
            "nullable": true,
            "description": "Last scan date"
          },
          "vulnerability_counts": {
            "type": "object",
            "properties": {
              "total": {
                "type": "integer"
              },
              "critical": {
                "type": "integer"
              },
              "high": {
                "type": "integer"
              },
              "medium": {
                "type": "integer"
              },
              "low": {
                "type": "integer"
              },
              "informational": {
                "type": "integer"
              }
            }
          },
          "created_at": {
            "type": "string",
            "format": "date-time"
          },
          "updated_at": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "Webhook": {
        "type": "object",
        "properties": {
          "id": {
            "type": "integer"
          },
          "user_id": {
            "type": "integer"
          },
          "url": {
            "type": "string",
            "format": "uri",
            "description": "HTTPS endpoint that receives events"
          },
          "secret": {
            "type": "string",
            "description": "HMAC-SHA256 signing secret (only visible when creating or updating)"
          },
          "events": {
            "type": "array",
            "items": {
              "type": "string",
              "enum": ["scan.completed", "scan.failed"]
            },
            "description": "Subscribed event types"
          },
          "description": {
            "type": "string",
            "nullable": true,
            "description": "User-provided description"
          },
          "is_active": {
            "type": "boolean",
            "description": "Whether the webhook is enabled"
          },
          "last_triggered_at": {
            "type": "string",
            "format": "date-time",
            "nullable": true,
            "description": "When the webhook last fired"
          },
          "created_at": {
            "type": "string",
            "format": "date-time"
          },
          "updated_at": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "WebhookDelivery": {
        "type": "object",
        "properties": {
          "id": {
            "type": "integer"
          },
          "webhook_id": {
            "type": "integer"
          },
          "event": {
            "type": "string",
            "description": "Event type that triggered this delivery",
            "example": "scan.completed"
          },
          "payload": {
            "type": "object",
            "description": "The JSON payload that was sent"
          },
          "response_code": {
            "type": "integer",
            "nullable": true,
            "description": "HTTP status code returned by the endpoint",
            "example": 200
          },
          "response_body": {
            "type": "string",
            "nullable": true,
            "description": "Response body from the endpoint (truncated)"
          },
          "attempts": {
            "type": "integer",
            "description": "Number of delivery attempts made",
            "example": 1
          },
          "success": {
            "type": "boolean",
            "description": "Whether the delivery was successful"
          },
          "next_retry_at": {
            "type": "string",
            "format": "date-time",
            "nullable": true,
            "description": "When the next retry will be attempted (if failed)"
          },
          "created_at": {
            "type": "string",
            "format": "date-time"
          },
          "updated_at": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "PaginationMeta": {
        "type": "object",
        "properties": {
          "current_page": {
            "type": "integer",
            "description": "Current page number"
          },
          "per_page": {
            "type": "integer",
            "description": "Items per page"
          },
          "total": {
            "type": "integer",
            "description": "Total number of items"
          },
          "last_page": {
            "type": "integer",
            "description": "Last page number"
          }
        }
      },
      "Error": {
        "type": "object",
        "properties": {
          "message": {
            "type": "string",
            "description": "Error message"
          }
        }
      },
      "ValidationError": {
        "type": "object",
        "properties": {
          "message": {
            "type": "string",
            "description": "Error message"
          },
          "errors": {
            "type": "object",
            "additionalProperties": {
              "type": "array",
              "items": {
                "type": "string"
              }
            },
            "description": "Field-specific validation errors"
          }
        }
      }
    },
    "responses": {
      "UnauthorizedError": {
        "description": "Authentication required or token invalid",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            },
            "example": {
              "message": "Unauthenticated"
            }
          }
        }
      },
      "NotFoundError": {
        "description": "Resource not found",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            },
            "example": {
              "message": "Resource not found"
            }
          }
        }
      },
      "ServerError": {
        "description": "Server error",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            },
            "example": {
              "message": "Internal server error"
            }
          }
        }
      }
    }
  },
  "security": [
    {
      "bearerAuth": []
    }
  ]
}
