{
  "openapi": "3.0.3",
  "info": {
    "title": "OneFirewall Offensive Security API",
    "description": "API endpoints for the Vulnix Scanner, user management, and configuration.\n\n## Authentication\n\nAuthentication is handled via API keys. You must include your key in the `api-key` header with every request.\n\n- **Header**: `api-key: {your-api-key}`\n- **Key Format**: A single secret string provided upon creation.\n\n## Organization Context\n\nFor endpoints requiring an organization context (like scanning), you can specify your organization ID:\n\n- **Header**: `X-Org-Id: {your-org-id}`\n- **Query Parameter**: `?org_id={your-org-id}`\n\nIf not provided, the request will use your default organization.",
    "version": "1.0.0"
  },
  "servers": [
    {
      "url": "https://vulnix0.com",
      "description": "Production server"
    }
  ],
  "components": {
    "securitySchemes": {
      "apiKeyAuth": {
        "type": "apiKey",
        "in": "header",
        "name": "api-key",
        "description": "A unique API Key."
      }
    },
    "schemas": {
      "InviteRequest": {
        "type": "object",
        "required": [
          "email"
        ],
        "properties": {
          "email": {
            "type": "string",
            "format": "email",
            "example": "new.user@example.com",
            "description": "Email address of the user to invite"
          }
        }
      },
      "LoginRequest": {
        "type": "object",
        "required": [
          "email"
        ],
        "properties": {
          "email": {
            "type": "string",
            "format": "email",
            "example": "user@example.com",
            "description": "Email address of the user to log in."
          }
        }
      },
      "VerifyTokenRequest": {
        "type": "object",
        "required": [
          "token"
        ],
        "properties": {
          "token": {
            "type": "string",
            "example": "a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6",
            "description": "The magic link token received via email."
          }
        }
      },
      "UpdateProfileRequest": {
        "type": "object",
        "properties": {
          "name": {
            "type": "string",
            "example": "John"
          },
          "surname": {
            "type": "string",
            "example": "Doe"
          },
          "company_name": {
            "type": "string",
            "example": "Cyber Corp"
          },
          "address": {
            "type": "string",
            "example": "123 Example St, Example City"
          },
          "receive_notification": {
            "type": "boolean",
            "example": true
          },
          "profile_picture_url": {
            "type": "string",
            "format": "uri",
            "example": "https://example.com/avatar.png",
            "description": "Must end with .png, .jpg, .jpeg, .webp, or .gif"
          }
        }
      },
      "AdvancedScanConfig": {
        "type": "object",
        "description": "Advanced configuration options for initiating a scan. Useful for authenticated testing, api scanning, and fine-tuning crawler limits.",
        "properties": {
          "web": {
            "type": "boolean",
            "description": "Enable web application scanning mode"
          },
          "fuzzing": {
            "type": "boolean",
            "description": "Enable fuzzing for deeper discovery"
          },
          "follow_links": {
            "type": "boolean",
            "description": "Follow links during crawling"
          },
          "exclude_paths": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Paths to exclude from scanning (e.g., ['/logout', '/delete'])"
          },
          "cookies": {
            "type": "string",
            "description": "Custom cookies to include in requests"
          },
          "proxy_usage": {
            "type": "string",
            "description": "Proxy URL to route scan traffic through"
          },
          "Authorization": {
            "type": "string",
            "description": "Authorization header value (e.g., Bearer token)"
          },
          "openapi_spec": {
            "type": "string",
            "description": "Raw JSON or YAML OpenAPI 2.x/3.x specification for API DAST scanning"
          },
          "openai_spec": {
            "type": "string",
            "description": "Alias for openapi_spec (handles common typos)"
          },
          "custom_headers": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "name": {
                  "type": "string"
                },
                "value": {
                  "type": "string"
                }
              }
            },
            "description": "Custom HTTP headers to include in requests"
          }
        }
      },
      "ScanPolicy": {
        "type": "object",
        "properties": {
          "ports_to_scan": {
            "type": "array",
            "items": {
              "type": "integer"
            },
            "example": [
              80,
              443,
              8080
            ],
            "description": "List of ports to scan"
          },
          "directory_enumeration": {
            "type": "boolean",
            "example": true,
            "description": "Enable directory enumeration"
          },
          "vhost_enumeration": {
            "type": "boolean",
            "example": false,
            "description": "Enable virtual host enumeration"
          }
        }
      },
      "ScanPolicyRequest": {
        "type": "object",
        "required": [
          "policy"
        ],
        "properties": {
          "policy": {
            "$ref": "#/components/schemas/ScanPolicy"
          }
        }
      },
      "ScanPolicyResponse": {
        "type": "object",
        "properties": {
          "email": {
            "type": "string",
            "format": "email"
          },
          "policy": {
            "$ref": "#/components/schemas/ScanPolicy"
          }
        }
      },
      "UserProfile": {
        "type": "object",
        "properties": {
          "email": {
            "type": "string",
            "format": "email"
          },
          "name": {
            "type": "string"
          },
          "surname": {
            "type": "string"
          },
          "company_name": {
            "type": "string"
          },
          "address": {
            "type": "string"
          },
          "receive_notification": {
            "type": "boolean"
          },
          "profile_picture_url": {
            "type": "string"
          }
        }
      },
      "APIKey": {
        "type": "object",
        "properties": {
          "prefix": {
            "type": "string",
            "description": "The first 8 characters of the API key for identification.",
            "example": "a1b2c3d4"
          },
          "created_at": {
            "type": "string",
            "format": "date-time"
          },
          "last_used_at": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "ScanResponse": {
        "type": "object",
        "properties": {
          "reqid": {
            "type": "string",
            "description": "Unique ID for this scan request",
            "format": "uuid"
          },
          "message": {
            "type": "string",
            "example": "Scan initiated for target: example.com"
          }
        }
      },
      "LightScan": {
        "type": "object",
        "properties": {
          "reqid": {
            "type": "string",
            "format": "uuid"
          },
          "status": {
            "type": "string",
            "enum": [
              "pending",
              "running",
              "completed",
              "failed"
            ]
          },
          "target": {
            "type": "string"
          },
          "created_at": {
            "type": "string",
            "format": "date-time"
          },
          "updated_at": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "ErrorResponse": {
        "type": "object",
        "properties": {
          "status": {
            "type": "string",
            "example": "error"
          },
          "error": {
            "type": "string",
            "example": "Error message description"
          }
        }
      },
      "SuccessResponse": {
        "type": "object",
        "properties": {
          "status": {
            "type": "string",
            "example": "success"
          },
          "message": {
            "type": "string"
          }
        }
      }
    },
    "responses": {
      "UnauthorizedError": {
        "description": "Authentication required or invalid credentials",
        "content": {
          "application/json": {
            "schema": {
              "type": "object",
              "properties": {
                "status": {
                  "type": "string",
                  "example": "error"
                },
                "message": {
                  "type": "string",
                  "example": "Missing or invalid API key"
                }
              }
            }
          }
        }
      }
    }
  },
  "security": [
    {
      "apiKeyAuth": []
    }
  ],
  "paths": {
    "/api/v1/login": {
      "post": {
        "summary": "Request Login Link",
        "description": "Requests a magic login link to be sent to the user's email. The user must already be invited to the platform.",
        "tags": [
          "Authentication"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/LoginRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Login link sent successfully.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "message": {
                      "type": "string",
                      "example": "Login link sent to your email"
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "User has not been invited.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/verify-token": {
      "post": {
        "summary": "Verify Magic Token",
        "description": "Verifies a magic link token and, if valid, returns a JWT session cookie to authenticate the user for subsequent requests.",
        "tags": [
          "Authentication"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/VerifyTokenRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Token verified and user logged in successfully.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SuccessResponse"
                }
              }
            }
          },
          "401": {
            "description": "Invalid or expired token.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/logout": {
      "post": {
        "summary": "Log Out",
        "description": "Logs the user out by clearing their authentication cookie. This requires the user to be authenticated (i.e., have a valid JWT cookie).",
        "tags": [
          "Authentication"
        ],
        "security": [
          {
            "apiKeyAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "Logged out successfully.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SuccessResponse"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/user/me": {
      "get": {
        "summary": "Get User Profile",
        "description": "Retrieves profile information for the authenticated user.",
        "tags": [
          "User Management"
        ],
        "responses": {
          "200": {
            "description": "User profile data",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/UserProfile"
                },
                "examples": {
                  "userProfileExample": {
                    "summary": "Example user profile",
                    "value": {
                      "email": "jsmith@example.com",
                      "name": "John",
                      "surname": "Smith",
                      "company_name": "Example Corp",
                      "address": "123 Example St, Example City",
                      "receive_notification": true,
                      "profile_picture_url": "https://example.com/profiles/jsmith.png"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/UnauthorizedError"
          }
        }
      },
      "post": {
        "summary": "Update User Profile",
        "description": "Updates profile information for the authenticated user.",
        "tags": [
          "User Management"
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UpdateProfileRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Profile updated successfully",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SuccessResponse"
                },
                "example": {
                  "status": "success",
                  "message": "Profile updated successfully"
                }
              }
            }
          },
          "400": {
            "description": "Bad request",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/invite": {
      "post": {
        "summary": "Invite User",
        "description": "Invites a new user to the platform.",
        "tags": [
          "User Management"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/InviteRequest"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "User invited successfully",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "message": {
                      "type": "string",
                      "example": "User invited successfully. A magic login link has been sent to their email."
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/scan/{target}": {
      "post": {
        "summary": "Initiate Scan",
        "description": "Starts a new vulnerability scan for a given target. The target is specified as the final part of the URL path.",
        "tags": [
          "Scan Management"
        ],
        "parameters": [
          {
            "name": "target",
            "in": "path",
            "required": true,
            "description": "Target to scan (domain, IP, or URL)",
            "schema": {
              "type": "string"
            },
            "examples": {
              "domain": {
                "value": "grok.com",
                "summary": "Simple domain"
              }
            }
          },
          {
            "name": "X-Org-Id",
            "in": "header",
            "required": false,
            "description": "Organization ID to associate the scan with",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "org_id",
            "in": "query",
            "required": false,
            "description": "Organization ID to associate the scan with",
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "description": "Optional advanced configuration for the scan",
          "required": false,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/AdvancedScanConfig"
              }
            }
          }
        },
        "responses": {
          "202": {
            "description": "Scan successfully initiated",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ScanResponse"
                },
                "examples": {
                  "scanInitiated": {
                    "summary": "Example scan initiation response",
                    "value": {
                      "message": "Scan initiated for target: grok.com (scanning on domain: grok.com)",
                      "reqid": "95e201b5-93bf-4218-8b96-6fb23b8874d3"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Invalid target",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/scans": {
      "get": {
        "summary": "List User Scans",
        "description": "Retrieves a list of all scans initiated by the authenticated user.",
        "tags": [
          "Scan Management"
        ],
        "responses": {
          "200": {
            "description": "List of user scans",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/LightScan"
                  }
                },
                "examples": {
                  "listOfScans": {
                    "summary": "Example list of user scans",
                    "value": [
                      {
                        "reqid": "95e201b5-93bf-4218-8b96-6fb23b8874d3",
                        "status": "running",
                        "target": "grok.com",
                        "created_at": "2025-10-13T03:29:31.349Z",
                        "updated_at": "2025-10-13T03:29:31.368Z"
                      },
                      {
                        "reqid": "f7a358e2-e8df-442b-9769-2f7455d983c6",
                        "status": "completed",
                        "target": "grok.com",
                        "created_at": "2025-10-13T03:18:48.945Z",
                        "updated_at": "2025-10-13T03:28:22.777Z"
                      }
                    ]
                  }
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/scans/{reqid}": {
      "get": {
        "summary": "Get Scan Details",
        "description": "Retrieves full results and status of a specific scan by its request ID.",
        "tags": [
          "Scan Management"
        ],
        "parameters": [
          {
            "name": "reqid",
            "in": "path",
            "required": true,
            "description": "Unique scan request ID (UUID)",
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Detailed scan results",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "status": {
                      "type": "string",
                      "enum": [
                        "pending",
                        "running",
                        "completed",
                        "failed"
                      ]
                    },
                    "data": {
                      "type": "object",
                      "description": "Full scan output"
                    }
                  }
                },
                "examples": {
                  "completedScan": {
                    "summary": "A completed scan with findings",
                    "value": {
                      "reqid": "f7a358e2-e8df-442b-9769-2f7455d983c6",
                      "status": "completed",
                      "target": "grok.com",
                      "data": {
                        "summary": {
                          "total_vulnerabilities": 2,
                          "high": 1,
                          "medium": 1
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "Scan not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          }
        }
      },
      "delete": {
        "summary": "Delete Scan",
        "description": "Deletes a scan record and its associated data by request ID.",
        "tags": [
          "Scan Management"
        ],
        "parameters": [
          {
            "name": "reqid",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Scan deleted successfully",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SuccessResponse"
                },
                "example": {
                  "status": "success",
                  "message": "Scan deleted successfully"
                }
              }
            }
          },
          "404": {
            "description": "Scan not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/user/apikeys": {
      "get": {
        "summary": "List API Keys",
        "description": "Retrieves metadata for all API keys belonging to the user.",
        "tags": [
          "API Keys"
        ],
        "responses": {
          "200": {
            "description": "A list of API key metadata.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/APIKey"
                  }
                }
              }
            }
          }
        }
      },
      "post": {
        "summary": "Create API Key",
        "description": "Generates a new API key. **Important**: The full key is only shown once. Store it securely.",
        "tags": [
          "API Keys"
        ],
        "responses": {
          "200": {
            "description": "New API key created.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "api_key": {
                      "type": "string",
                      "example": "a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6",
                      "description": "Full API key (shown only once)"
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/user/apikeys/{index_key}": {
      "delete": {
        "summary": "Delete API Key",
        "description": "Revokes and deletes an API key using its public prefix.",
        "tags": [
          "API Keys"
        ],
        "parameters": [
          {
            "name": "index_key",
            "in": "path",
            "required": true,
            "description": "The first 8 characters of the API key.",
            "schema": {
              "type": "string",
              "pattern": "^[a-f0-9]{8}$",
              "example": "a1b2c3d4"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "API key deleted successfully",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SuccessResponse"
                },
                "example": {
                  "status": "success",
                  "message": "API key deleted successfully"
                }
              }
            }
          },
          "404": {
            "description": "API key not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/user/scan-policy": {
      "get": {
        "summary": "Get Scan Policy",
        "description": "Retrieves the custom scan policy for the user.",
        "tags": [
          "Configuration"
        ],
        "responses": {
          "200": {
            "description": "User's current scan policy",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ScanPolicyResponse"
                }
              }
            }
          },
          "404": {
            "description": "No scan policy found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          }
        }
      },
      "post": {
        "summary": "Update Scan Policy",
        "description": "Creates or updates the user's custom scan policy.",
        "tags": [
          "Configuration"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ScanPolicyRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Scan policy updated",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SuccessResponse"
                },
                "example": {
                  "status": "success",
                  "message": "Scan policy updated successfully"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/health": {
      "get": {
        "summary": "Health Check",
        "description": "Verifies the API is running and responding.",
        "tags": [
          "Utilities"
        ],
        "security": [],
        "responses": {
          "200": {
            "description": "API is healthy",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "status": {
                      "type": "string",
                      "example": "ok"
                    }
                  }
                }
              }
            }
          }
        }
      }
    }
  }
}