Files
SneakyScan/docs/API_REFERENCE.md

60 KiB

SneakyScanner Web API Reference

Version: 5.0 (Phase 5) Base URL: http://localhost:5000 Authentication: Session-based (Flask-Login)

Table of Contents

  1. Authentication
  2. Scans API
  3. Configs API
  4. Schedules API
  5. Stats API
  6. Settings API
  7. Alerts API
  8. Webhooks API
  9. Error Handling
  10. Status Codes
  11. Request/Response Examples

Authentication

SneakyScanner uses session-based authentication with Flask-Login. All API endpoints (except login, setup, and health checks) require authentication.

Setup

Initial password setup for first-time use.

Endpoint: GET|POST /auth/setup

Authentication: Not required (only accessible when no password is set)

GET Request: Returns the setup page template.

POST Request Body:

password: "your-password-here"
confirm_password: "your-password-here"

Success Response: Redirects to login page (302)

Error Responses:

  • Password must be at least 8 characters
  • Passwords must match
  • Password is required

Usage Example:

# Setup initial password
curl -X POST http://localhost:5000/auth/setup \
  -F "password=yourpassword" \
  -F "confirm_password=yourpassword"

Login

Authenticate and create a session.

Endpoint: POST /auth/login

Authentication: Not required

Request Body:

password: "your-password-here"
remember: false (optional)

Success Response: Redirects to dashboard (302)

Error Response: Returns login page with error message

Usage Example:

# Login and save session cookie
curl -X POST http://localhost:5000/auth/login \
  -F "password=yourpassword" \
  -c cookies.txt

# Use session cookie for subsequent requests
curl -X GET http://localhost:5000/api/scans \
  -b cookies.txt

Logout

Destroy the current session.

Endpoint: GET /auth/logout

Success Response: Redirects to login page (302)


Scans API

Manage network scans: trigger, list, view, and delete.

Trigger Scan

Start a new background scan.

Endpoint: POST /api/scans

Authentication: Required

Request Body:

{
  "config_file": "/app/configs/example-site.yaml"
}

Success Response (201 Created):

{
  "scan_id": 42,
  "status": "running",
  "message": "Scan queued successfully"
}

Error Responses:

400 Bad Request - Invalid config file:

{
  "error": "Invalid config file",
  "message": "Config file does not exist or is not valid YAML"
}

500 Internal Server Error - Scan queue failure:

{
  "error": "Failed to queue scan",
  "message": "Internal server error"
}

Usage Example:

curl -X POST http://localhost:5000/api/scans \
  -H "Content-Type: application/json" \
  -d '{"config_file":"/app/configs/production.yaml"}' \
  -b cookies.txt

List Scans

Retrieve a paginated list of scans with optional status filtering.

Endpoint: GET /api/scans

Authentication: Required

Query Parameters:

Parameter Type Required Default Description
page integer No 1 Page number (1-indexed)
per_page integer No 20 Items per page (1-100)
status string No - Filter by status: running, completed, failed

Success Response (200 OK):

{
  "scans": [
    {
      "id": 42,
      "timestamp": "2025-11-14T10:30:00Z",
      "duration": 125.5,
      "status": "completed",
      "title": "Production Network Scan",
      "config_file": "/app/configs/production.yaml",
      "triggered_by": "manual",
      "started_at": "2025-11-14T10:30:00Z",
      "completed_at": "2025-11-14T10:32:05Z"
    },
    {
      "id": 41,
      "timestamp": "2025-11-13T15:00:00Z",
      "duration": 98.2,
      "status": "completed",
      "title": "Development Network Scan",
      "config_file": "/app/configs/dev.yaml",
      "triggered_by": "scheduled",
      "started_at": "2025-11-13T15:00:00Z",
      "completed_at": "2025-11-13T15:01:38Z"
    }
  ],
  "total": 42,
  "page": 1,
  "per_page": 20,
  "total_pages": 3,
  "has_prev": false,
  "has_next": true
}

Error Responses:

400 Bad Request - Invalid parameters:

{
  "error": "Invalid pagination parameters",
  "message": "Page and per_page must be positive integers"
}

Usage Examples:

# List first page (default 20 items)
curl -X GET http://localhost:5000/api/scans \
  -b cookies.txt

# List page 2 with 50 items per page
curl -X GET "http://localhost:5000/api/scans?page=2&per_page=50" \
  -b cookies.txt

# List only running scans
curl -X GET "http://localhost:5000/api/scans?status=running" \
  -b cookies.txt

Get Scan Details

Retrieve complete details for a specific scan, including all sites, IPs, ports, services, certificates, and TLS versions.

Endpoint: GET /api/scans/{id}

Authentication: Required

Path Parameters:

Parameter Type Required Description
id integer Yes Scan ID

Success Response (200 OK):

{
  "id": 42,
  "timestamp": "2025-11-14T10:30:00Z",
  "duration": 125.5,
  "status": "completed",
  "title": "Production Network Scan",
  "config_file": "/app/configs/production.yaml",
  "json_path": "/app/output/scan_report_20251114_103000.json",
  "html_path": "/app/output/scan_report_20251114_103000.html",
  "zip_path": "/app/output/scan_report_20251114_103000.zip",
  "screenshot_dir": "/app/output/scan_report_20251114_103000_screenshots",
  "triggered_by": "manual",
  "started_at": "2025-11-14T10:30:00Z",
  "completed_at": "2025-11-14T10:32:05Z",
  "error_message": null,
  "sites": [
    {
      "id": 101,
      "site_name": "Production Web Servers",
      "ips": [
        {
          "id": 201,
          "ip_address": "192.168.1.10",
          "ping_expected": true,
          "ping_actual": true,
          "ports": [
            {
              "id": 301,
              "port": 443,
              "protocol": "tcp",
              "expected": true,
              "state": "open",
              "services": [
                {
                  "id": 401,
                  "service_name": "https",
                  "product": "nginx",
                  "version": "1.24.0",
                  "extrainfo": null,
                  "ostype": "Linux",
                  "http_protocol": "https",
                  "screenshot_path": "scan_report_20251114_103000_screenshots/192_168_1_10_443.png",
                  "certificates": [
                    {
                      "id": 501,
                      "subject": "CN=example.com",
                      "issuer": "CN=Let's Encrypt Authority X3,O=Let's Encrypt,C=US",
                      "serial_number": "123456789012345678901234567890",
                      "not_valid_before": "2025-01-01T00:00:00+00:00",
                      "not_valid_after": "2025-04-01T23:59:59+00:00",
                      "days_until_expiry": 89,
                      "sans": "[\"example.com\", \"www.example.com\"]",
                      "is_self_signed": false,
                      "tls_versions": [
                        {
                          "id": 601,
                          "tls_version": "TLS 1.2",
                          "supported": true,
                          "cipher_suites": "[\"TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384\", \"TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256\"]"
                        },
                        {
                          "id": 602,
                          "tls_version": "TLS 1.3",
                          "supported": true,
                          "cipher_suites": "[\"TLS_AES_256_GCM_SHA384\", \"TLS_AES_128_GCM_SHA256\"]"
                        }
                      ]
                    }
                  ]
                }
              ]
            }
          ]
        }
      ]
    }
  ]
}

Error Responses:

404 Not Found - Scan doesn't exist:

{
  "error": "Scan not found",
  "message": "Scan with ID 42 does not exist"
}

Usage Example:

curl -X GET http://localhost:5000/api/scans/42 \
  -b cookies.txt

Get Scan Status

Poll the current status of a running scan. Use this endpoint to track scan progress.

Endpoint: GET /api/scans/{id}/status

Authentication: Required

Path Parameters:

Parameter Type Required Description
id integer Yes Scan ID

Success Response (200 OK):

Running scan:

{
  "scan_id": 42,
  "status": "running",
  "started_at": "2025-11-14T10:30:00Z",
  "completed_at": null,
  "error_message": null
}

Completed scan:

{
  "scan_id": 42,
  "status": "completed",
  "started_at": "2025-11-14T10:30:00Z",
  "completed_at": "2025-11-14T10:32:05Z",
  "error_message": null
}

Failed scan:

{
  "scan_id": 42,
  "status": "failed",
  "started_at": "2025-11-14T10:30:00Z",
  "completed_at": "2025-11-14T10:30:15Z",
  "error_message": "Config file not found: /app/configs/missing.yaml"
}

Error Responses:

404 Not Found - Scan doesn't exist:

{
  "error": "Scan not found",
  "message": "Scan with ID 42 does not exist"
}

Usage Example:

# Poll status every 5 seconds
while true; do
  curl -X GET http://localhost:5000/api/scans/42/status -b cookies.txt
  sleep 5
done

Delete Scan

Delete a scan and all associated files (JSON, HTML, ZIP, screenshots).

Endpoint: DELETE /api/scans/{id}

Authentication: Required

Path Parameters:

Parameter Type Required Description
id integer Yes Scan ID

Success Response (200 OK):

{
  "message": "Scan 42 deleted successfully"
}

Error Responses:

404 Not Found - Scan doesn't exist:

{
  "error": "Scan not found",
  "message": "Scan with ID 42 does not exist"
}

Usage Example:

curl -X DELETE http://localhost:5000/api/scans/42 \
  -b cookies.txt

Compare Scans

Compare two scans to identify differences in ports, services, and certificates.

Endpoint: GET /api/scans/{scan_id1}/compare/{scan_id2}

Authentication: Required

Path Parameters:

Parameter Type Required Description
scan_id1 integer Yes First (older) scan ID
scan_id2 integer Yes Second (newer) scan ID

Success Response (200 OK):

{
  "scan1": {
    "id": 41,
    "timestamp": "2025-11-13T15:00:00Z",
    "title": "Development Network Scan"
  },
  "scan2": {
    "id": 42,
    "timestamp": "2025-11-14T10:30:00Z",
    "title": "Production Network Scan"
  },
  "ports": {
    "added": [{"ip": "192.168.1.10", "port": 8080, "protocol": "tcp"}],
    "removed": [{"ip": "192.168.1.11", "port": 22, "protocol": "tcp"}],
    "unchanged": [{"ip": "192.168.1.10", "port": 443, "protocol": "tcp"}]
  },
  "services": {
    "added": [{"ip": "192.168.1.10", "port": 8080, "service_name": "http-proxy"}],
    "removed": [{"ip": "192.168.1.11", "port": 22, "service_name": "ssh"}],
    "changed": [
      {
        "ip": "192.168.1.10",
        "port": 443,
        "old_version": "1.23.0",
        "new_version": "1.24.0"
      }
    ]
  },
  "certificates": {
    "added": [],
    "removed": [],
    "changed": [
      {
        "ip": "192.168.1.10",
        "port": 443,
        "old_expiry": "2025-04-01",
        "new_expiry": "2025-07-01"
      }
    ]
  },
  "drift_score": 0.15
}

Error Responses:

404 Not Found - One or both scans don't exist:

{
  "error": "Not found",
  "message": "One or both scans not found"
}

Usage Example:

curl -X GET http://localhost:5000/api/scans/41/compare/42 \
  -b cookies.txt

Health Check

Check API health status.

Endpoint: GET /api/scans/health

Authentication: Not required

Success Response (200 OK):

{
  "status": "healthy",
  "api": "scans",
  "version": "1.0.0-phase1"
}

Configs API

Manage scan configuration files including creation, upload, editing, and deletion.

List Configs

Retrieve a list of all available configuration files.

Endpoint: GET /api/configs

Authentication: Required

Success Response (200 OK):

{
  "configs": [
    {
      "filename": "prod-scan.yaml",
      "title": "Production Scan",
      "path": "/app/configs/prod-scan.yaml",
      "created_at": "2025-11-15T10:30:00Z",
      "size_bytes": 1234,
      "used_by_schedules": ["Daily Production Scan"]
    }
  ]
}

Usage Example:

curl -X GET http://localhost:5000/api/configs \
  -b cookies.txt

Get Config

Retrieve a specific configuration file's content and parsed data.

Endpoint: GET /api/configs/{filename}

Authentication: Required

Path Parameters:

Parameter Type Required Description
filename string Yes Config filename

Success Response (200 OK):

{
  "filename": "prod-scan.yaml",
  "content": "title: Production Scan\nsites:\n  - ...",
  "parsed": {
    "title": "Production Scan",
    "sites": [...]
  }
}

Error Responses:

404 Not Found - Config file doesn't exist:

{
  "error": "Not found",
  "message": "Config file not found"
}

400 Bad Request - Invalid YAML:

{
  "error": "Invalid config",
  "message": "YAML parsing error details"
}

Usage Example:

curl -X GET http://localhost:5000/api/configs/prod-scan.yaml \
  -b cookies.txt

Create Config from CIDR

Create a new configuration file from a CIDR range.

Endpoint: POST /api/configs/create-from-cidr

Authentication: Required

Request Body:

{
  "title": "My Network Scan",
  "cidr": "10.0.0.0/24",
  "site_name": "Production Network",
  "ping_default": false
}

Success Response (200 OK):

{
  "success": true,
  "filename": "my-network-scan.yaml",
  "preview": "title: My Network Scan\nsites:\n  - ..."
}

Error Responses:

400 Bad Request - Missing required fields or invalid CIDR:

{
  "error": "Validation error",
  "message": "Invalid CIDR range"
}

Usage Example:

curl -X POST http://localhost:5000/api/configs/create-from-cidr \
  -H "Content-Type: application/json" \
  -d '{"title":"My Scan","cidr":"10.0.0.0/24"}' \
  -b cookies.txt

Upload YAML Config

Upload a YAML configuration file directly.

Endpoint: POST /api/configs/upload-yaml

Authentication: Required

Request Body:

file: <yaml file>
filename: "custom-name.yaml" (optional)

Success Response (200 OK):

{
  "success": true,
  "filename": "custom-name.yaml"
}

Error Responses:

400 Bad Request - No file or invalid YAML:

{
  "error": "Validation error",
  "message": "File must be a YAML file (.yaml or .yml extension)"
}

Usage Example:

curl -X POST http://localhost:5000/api/configs/upload-yaml \
  -F "file=@/path/to/config.yaml" \
  -b cookies.txt

Download Config

Download an existing configuration file.

Endpoint: GET /api/configs/{filename}/download

Authentication: Required

Path Parameters:

Parameter Type Required Description
filename string Yes Config filename

Success Response (200 OK): Returns YAML file as download.

Usage Example:

curl -X GET http://localhost:5000/api/configs/prod-scan.yaml/download \
  -b cookies.txt \
  -o prod-scan.yaml

Update Config

Update an existing configuration file with new YAML content.

Endpoint: PUT /api/configs/{filename}

Authentication: Required

Path Parameters:

Parameter Type Required Description
filename string Yes Config filename

Request Body:

{
  "content": "title: Updated Scan\nsites:\n  - ..."
}

Success Response (200 OK):

{
  "success": true,
  "message": "Config updated successfully"
}

Error Responses:

404 Not Found - Config file doesn't exist:

{
  "error": "Not found",
  "message": "Config file not found"
}

400 Bad Request - Invalid YAML:

{
  "error": "Validation error",
  "message": "Invalid YAML structure"
}

Usage Example:

curl -X PUT http://localhost:5000/api/configs/prod-scan.yaml \
  -H "Content-Type: application/json" \
  -d '{"content":"title: Updated\nsites: []"}' \
  -b cookies.txt

Delete Config

Delete a configuration file and cascade delete associated schedules.

Endpoint: DELETE /api/configs/{filename}

Authentication: Required

Path Parameters:

Parameter Type Required Description
filename string Yes Config filename

Success Response (200 OK):

{
  "success": true,
  "message": "Config deleted successfully"
}

Error Responses:

404 Not Found - Config file doesn't exist:

{
  "error": "Not found",
  "message": "Config file not found"
}

Usage Example:

curl -X DELETE http://localhost:5000/api/configs/prod-scan.yaml \
  -b cookies.txt

Schedules API

Manage scheduled scans including creation, updates, and manual triggering.

List Schedules

Retrieve a list of all schedules with pagination and filtering.

Endpoint: GET /api/schedules

Authentication: Required

Query Parameters:

Parameter Type Required Default Description
page integer No 1 Page number (1-indexed)
per_page integer No 20 Items per page
enabled boolean No - Filter by enabled status (true/false)

Success Response (200 OK):

{
  "schedules": [
    {
      "id": 1,
      "name": "Daily Production Scan",
      "config_file": "/app/configs/prod-scan.yaml",
      "cron_expression": "0 2 * * *",
      "enabled": true,
      "created_at": "2025-11-01T10:00:00Z",
      "updated_at": "2025-11-01T10:00:00Z",
      "last_run": "2025-11-15T02:00:00Z",
      "next_run": "2025-11-16T02:00:00Z"
    }
  ],
  "total": 5,
  "page": 1,
  "per_page": 20,
  "total_pages": 1
}

Usage Example:

# List all schedules
curl -X GET http://localhost:5000/api/schedules \
  -b cookies.txt

# List only enabled schedules
curl -X GET "http://localhost:5000/api/schedules?enabled=true" \
  -b cookies.txt

Get Schedule

Retrieve details for a specific schedule including execution history.

Endpoint: GET /api/schedules/{schedule_id}

Authentication: Required

Path Parameters:

Parameter Type Required Description
schedule_id integer Yes Schedule ID

Success Response (200 OK):

{
  "id": 1,
  "name": "Daily Production Scan",
  "config_file": "/app/configs/prod-scan.yaml",
  "cron_expression": "0 2 * * *",
  "enabled": true,
  "created_at": "2025-11-01T10:00:00Z",
  "updated_at": "2025-11-01T10:00:00Z",
  "last_run": "2025-11-15T02:00:00Z",
  "next_run": "2025-11-16T02:00:00Z",
  "execution_history": [
    {
      "scan_id": 42,
      "timestamp": "2025-11-15T02:00:00Z",
      "status": "completed"
    }
  ]
}

Error Responses:

404 Not Found - Schedule doesn't exist:

{
  "error": "Schedule not found"
}

Usage Example:

curl -X GET http://localhost:5000/api/schedules/1 \
  -b cookies.txt

Create Schedule

Create a new scheduled scan.

Endpoint: POST /api/schedules

Authentication: Required

Request Body:

{
  "name": "Daily Production Scan",
  "config_file": "/app/configs/prod-scan.yaml",
  "cron_expression": "0 2 * * *",
  "enabled": true
}

Success Response (201 Created):

{
  "schedule_id": 1,
  "message": "Schedule created successfully",
  "schedule": {
    "id": 1,
    "name": "Daily Production Scan",
    "config_file": "/app/configs/prod-scan.yaml",
    "cron_expression": "0 2 * * *",
    "enabled": true,
    "created_at": "2025-11-01T10:00:00Z"
  }
}

Error Responses:

400 Bad Request - Missing required fields or invalid cron expression:

{
  "error": "Missing required fields: name, config_file"
}

Usage Example:

curl -X POST http://localhost:5000/api/schedules \
  -H "Content-Type: application/json" \
  -d '{"name":"Daily Scan","config_file":"/app/configs/prod.yaml","cron_expression":"0 2 * * *"}' \
  -b cookies.txt

Update Schedule

Update an existing schedule.

Endpoint: PUT /api/schedules/{schedule_id}

Authentication: Required

Path Parameters:

Parameter Type Required Description
schedule_id integer Yes Schedule ID to update

Request Body:

{
  "name": "Updated Schedule Name",
  "cron_expression": "0 3 * * *",
  "enabled": false
}

Success Response (200 OK):

{
  "message": "Schedule updated successfully",
  "schedule": {
    "id": 1,
    "name": "Updated Schedule Name",
    "config_file": "/app/configs/prod-scan.yaml",
    "cron_expression": "0 3 * * *",
    "enabled": false,
    "updated_at": "2025-11-15T10:00:00Z"
  }
}

Error Responses:

404 Not Found - Schedule doesn't exist:

{
  "error": "Schedule not found"
}

400 Bad Request - Invalid cron expression or validation error:

{
  "error": "Invalid cron expression"
}

Usage Example:

curl -X PUT http://localhost:5000/api/schedules/1 \
  -H "Content-Type: application/json" \
  -d '{"enabled":false}' \
  -b cookies.txt

Delete Schedule

Delete a schedule. Associated scans are not deleted.

Endpoint: DELETE /api/schedules/{schedule_id}

Authentication: Required

Path Parameters:

Parameter Type Required Description
schedule_id integer Yes Schedule ID to delete

Success Response (200 OK):

{
  "message": "Schedule deleted successfully",
  "schedule_id": 1
}

Error Responses:

404 Not Found - Schedule doesn't exist:

{
  "error": "Schedule not found"
}

Usage Example:

curl -X DELETE http://localhost:5000/api/schedules/1 \
  -b cookies.txt

Trigger Schedule

Manually trigger a scheduled scan immediately.

Endpoint: POST /api/schedules/{schedule_id}/trigger

Authentication: Required

Path Parameters:

Parameter Type Required Description
schedule_id integer Yes Schedule ID to trigger

Success Response (201 Created):

{
  "message": "Scan triggered successfully",
  "schedule_id": 1,
  "scan_id": 43
}

Error Responses:

404 Not Found - Schedule doesn't exist:

{
  "error": "Schedule not found"
}

Usage Example:

curl -X POST http://localhost:5000/api/schedules/1/trigger \
  -b cookies.txt

Health Check

Check API health status.

Endpoint: GET /api/schedules/health

Authentication: Not required

Success Response (200 OK):

{
  "status": "healthy",
  "api": "schedules",
  "version": "1.0.0-phase1"
}

Stats API

Retrieve dashboard statistics, trends, and analytics data.

Scan Trend

Get scan activity trend data for charts.

Endpoint: GET /api/stats/scan-trend

Authentication: Required

Query Parameters:

Parameter Type Required Default Description
days integer No 30 Number of days to include (1-365)

Success Response (200 OK):

{
  "labels": ["2025-01-01", "2025-01-02", "2025-01-03"],
  "values": [5, 3, 7],
  "start_date": "2025-01-01",
  "end_date": "2025-01-30",
  "total_scans": 150
}

Error Responses:

400 Bad Request - Invalid days parameter:

{
  "error": "days parameter must be at least 1"
}

Usage Example:

# Get last 30 days trend
curl -X GET http://localhost:5000/api/stats/scan-trend \
  -b cookies.txt

# Get last 90 days trend
curl -X GET "http://localhost:5000/api/stats/scan-trend?days=90" \
  -b cookies.txt

Summary Statistics

Get dashboard summary statistics.

Endpoint: GET /api/stats/summary

Authentication: Required

Success Response (200 OK):

{
  "total_scans": 150,
  "completed_scans": 140,
  "failed_scans": 5,
  "running_scans": 5,
  "scans_today": 3,
  "scans_this_week": 15
}

Usage Example:

curl -X GET http://localhost:5000/api/stats/summary \
  -b cookies.txt

Scan History

Get historical trend data for scans with the same configuration.

Endpoint: GET /api/stats/scan-history/{scan_id}

Authentication: Required

Path Parameters:

Parameter Type Required Description
scan_id integer Yes Reference scan ID

Query Parameters:

Parameter Type Required Default Description
limit integer No 10 Max historical scans (1-50)

Success Response (200 OK):

{
  "scans": [
    {
      "id": 40,
      "timestamp": "2025-11-10T12:00:00",
      "title": "Production Scan",
      "port_count": 25,
      "ip_count": 5
    },
    {
      "id": 42,
      "timestamp": "2025-11-15T12:00:00",
      "title": "Production Scan",
      "port_count": 26,
      "ip_count": 5
    }
  ],
  "labels": ["2025-11-10 12:00", "2025-11-15 12:00"],
  "port_counts": [25, 26],
  "config_file": "/app/configs/prod-scan.yaml"
}

Error Responses:

404 Not Found - Scan doesn't exist:

{
  "error": "Scan not found"
}

Usage Example:

curl -X GET http://localhost:5000/api/stats/scan-history/42 \
  -b cookies.txt

Settings API

Manage application settings including SMTP configuration, encryption keys, and preferences.

Get All Settings

Retrieve all application settings. Sensitive values (passwords, keys) are masked.

Endpoint: GET /api/settings

Authentication: Required

Success Response (200 OK):

{
  "status": "success",
  "settings": {
    "smtp_server": "smtp.gmail.com",
    "smtp_port": 587,
    "smtp_username": "alerts@example.com",
    "smtp_password": "***ENCRYPTED***",
    "smtp_from_email": "alerts@example.com",
    "smtp_to_emails": "[\"admin@example.com\"]",
    "retention_days": 90,
    "app_password": "***ENCRYPTED***"
  }
}

Usage Example:

curl -X GET http://localhost:5000/api/settings \
  -b cookies.txt

Update Multiple Settings

Update multiple settings at once.

Endpoint: PUT /api/settings

Authentication: Required

Request Body:

{
  "settings": {
    "smtp_server": "smtp.example.com",
    "smtp_port": 587,
    "retention_days": 90
  }
}

Success Response (200 OK):

{
  "status": "success",
  "message": "Updated 3 settings"
}

Error Responses:

400 Bad Request - No settings provided:

{
  "status": "error",
  "message": "No settings provided"
}

Usage Example:

curl -X PUT http://localhost:5000/api/settings \
  -H "Content-Type: application/json" \
  -d '{"settings":{"smtp_server":"smtp.example.com","smtp_port":587}}' \
  -b cookies.txt

Get Single Setting

Retrieve a specific setting by key.

Endpoint: GET /api/settings/{key}

Authentication: Required

Path Parameters:

Parameter Type Required Description
key string Yes Setting key

Success Response (200 OK):

{
  "status": "success",
  "key": "smtp_server",
  "value": "smtp.gmail.com"
}

Error Responses:

404 Not Found - Setting doesn't exist:

{
  "status": "error",
  "message": "Setting \"invalid_key\" not found"
}

Usage Example:

curl -X GET http://localhost:5000/api/settings/smtp_server \
  -b cookies.txt

Update Single Setting

Update a specific setting value.

Endpoint: PUT /api/settings/{key}

Authentication: Required

Path Parameters:

Parameter Type Required Description
key string Yes Setting key

Request Body:

{
  "value": "smtp.example.com"
}

Success Response (200 OK):

{
  "status": "success",
  "message": "Setting \"smtp_server\" updated"
}

Error Responses:

400 Bad Request - Missing value:

{
  "status": "error",
  "message": "No value provided"
}

Usage Example:

curl -X PUT http://localhost:5000/api/settings/smtp_server \
  -H "Content-Type: application/json" \
  -d '{"value":"smtp.example.com"}' \
  -b cookies.txt

Delete Setting

Delete a specific setting.

Endpoint: DELETE /api/settings/{key}

Authentication: Required

Path Parameters:

Parameter Type Required Description
key string Yes Setting key to delete

Success Response (200 OK):

{
  "status": "success",
  "message": "Setting \"custom_key\" deleted"
}

Error Responses:

404 Not Found - Setting doesn't exist:

{
  "status": "error",
  "message": "Setting \"invalid_key\" not found"
}

Usage Example:

curl -X DELETE http://localhost:5000/api/settings/custom_key \
  -b cookies.txt

Set Application Password

Set or update the application password.

Endpoint: POST /api/settings/password

Authentication: Required

Request Body:

{
  "password": "newpassword123"
}

Success Response (200 OK):

{
  "status": "success",
  "message": "Password updated successfully"
}

Error Responses:

400 Bad Request - Missing or invalid password:

{
  "status": "error",
  "message": "Password must be at least 8 characters"
}

Usage Example:

curl -X POST http://localhost:5000/api/settings/password \
  -H "Content-Type: application/json" \
  -d '{"password":"newpassword123"}' \
  -b cookies.txt

Test Email Configuration

Test email settings by sending a test email.

Endpoint: POST /api/settings/test-email

Authentication: Required

Success Response (501 Not Implemented):

{
  "status": "not_implemented",
  "message": "Email testing endpoint - to be implemented in Phase 4"
}

Note: This endpoint returns 501 Not Implemented. Full email testing functionality will be added in a future phase.

Usage Example:

curl -X POST http://localhost:5000/api/settings/test-email \
  -b cookies.txt

Health Check

Check API health status.

Endpoint: GET /api/settings/health

Authentication: Not required

Success Response (200 OK):

{
  "status": "healthy",
  "api": "settings",
  "version": "1.0.0-phase1"
}

Usage Example:

curl -X GET http://localhost:5000/api/settings/health

Alerts API

Manage alert history and alert rules with full support for filtering, acknowledgment, and statistics.

List Alerts

List recent alerts with pagination and extensive filtering options.

Endpoint: GET /api/alerts

Authentication: Required

Query Parameters:

Parameter Type Required Default Description
page integer No 1 Page number (1-indexed)
per_page integer No 20 Items per page (1-100)
alert_type string No - Filter by alert type (unexpected_port, drift_detection, cert_expiry, weak_tls, ping_failed)
severity string No - Filter by severity (info, warning, critical)
acknowledged boolean No - Filter by acknowledgment status (true/false)
scan_id integer No - Filter by specific scan ID
start_date string No - Filter alerts after this date (ISO format)
end_date string No - Filter alerts before this date (ISO format)

Success Response (200 OK):

{
  "alerts": [
    {
      "id": 1,
      "scan_id": 42,
      "scan_title": "Production Network Scan",
      "rule_id": 3,
      "alert_type": "cert_expiry",
      "severity": "warning",
      "message": "Certificate for 192.168.1.10:443 expires in 15 days",
      "ip_address": "192.168.1.10",
      "port": 443,
      "acknowledged": false,
      "acknowledged_at": null,
      "acknowledged_by": null,
      "email_sent": true,
      "email_sent_at": "2025-11-18T10:30:00Z",
      "webhook_sent": false,
      "webhook_sent_at": null,
      "created_at": "2025-11-18T10:30:00Z"
    }
  ],
  "total": 1,
  "page": 1,
  "per_page": 20,
  "pages": 1
}

Usage Examples:

# List all alerts
curl -X GET http://localhost:5000/api/alerts \
  -b cookies.txt

# List only critical unacknowledged alerts
curl -X GET "http://localhost:5000/api/alerts?severity=critical&acknowledged=false" \
  -b cookies.txt

# List alerts for a specific scan
curl -X GET "http://localhost:5000/api/alerts?scan_id=42" \
  -b cookies.txt

# List alerts from last week
START_DATE=$(date -d '7 days ago' -Iseconds)
curl -X GET "http://localhost:5000/api/alerts?start_date=$START_DATE" \
  -b cookies.txt

Acknowledge Alert

Mark an alert as acknowledged.

Endpoint: POST /api/alerts/{alert_id}/acknowledge

Authentication: Required

Path Parameters:

Parameter Type Required Description
alert_id integer Yes Alert ID to acknowledge

Request Body (Optional):

{
  "acknowledged_by": "admin"
}

Success Response (200 OK):

{
  "status": "success",
  "message": "Alert 1 acknowledged",
  "acknowledged_by": "admin"
}

Error Responses:

400 Bad Request - Failed to acknowledge:

{
  "status": "error",
  "message": "Failed to acknowledge alert 1"
}

Usage Example:

curl -X POST http://localhost:5000/api/alerts/1/acknowledge \
  -H "Content-Type: application/json" \
  -d '{"acknowledged_by":"admin"}' \
  -b cookies.txt

List Alert Rules

List all configured alert rules.

Endpoint: GET /api/alerts/rules

Authentication: Required

Success Response (200 OK):

{
  "rules": [
    {
      "id": 1,
      "name": "Certificate Expiry Warning",
      "rule_type": "cert_expiry",
      "enabled": true,
      "threshold": 30,
      "email_enabled": true,
      "webhook_enabled": false,
      "severity": "warning",
      "filter_conditions": {
        "ip_pattern": "192.168.*"
      },
      "config_file": "/app/configs/production.yaml",
      "created_at": "2025-11-01T10:00:00Z",
      "updated_at": "2025-11-15T08:30:00Z"
    }
  ],
  "total": 1
}

Usage Example:

curl -X GET http://localhost:5000/api/alerts/rules \
  -b cookies.txt

Create Alert Rule

Create a new alert rule.

Endpoint: POST /api/alerts/rules

Authentication: Required

Request Body:

{
  "name": "Certificate Expiry Warning",
  "rule_type": "cert_expiry",
  "threshold": 30,
  "enabled": true,
  "email_enabled": true,
  "webhook_enabled": false,
  "severity": "warning",
  "filter_conditions": {
    "ip_pattern": "192.168.*"
  },
  "config_file": "/app/configs/production.yaml"
}

Request Body Fields:

Field Type Required Description
name string No User-friendly rule name (defaults to "{rule_type} rule")
rule_type string Yes Type of alert (unexpected_port, drift_detection, cert_expiry, weak_tls, ping_failed)
threshold integer No Threshold value (e.g., days for cert expiry, percentage for drift)
enabled boolean No Whether rule is active (default: true)
email_enabled boolean No Send email for this rule (default: false)
webhook_enabled boolean No Send webhook for this rule (default: false)
severity string No Alert severity: critical, warning, info (default: warning)
filter_conditions object No JSON object with filter conditions
config_file string No Config file to apply rule to (null for all configs)

Success Response (201 Created):

{
  "status": "success",
  "message": "Alert rule created successfully",
  "rule": {
    "id": 1,
    "name": "Certificate Expiry Warning",
    "rule_type": "cert_expiry",
    "enabled": true,
    "threshold": 30,
    "email_enabled": true,
    "webhook_enabled": false,
    "severity": "warning",
    "filter_conditions": {
      "ip_pattern": "192.168.*"
    },
    "config_file": "/app/configs/production.yaml",
    "created_at": "2025-11-18T10:00:00Z",
    "updated_at": "2025-11-18T10:00:00Z"
  }
}

Error Responses:

400 Bad Request - Missing or invalid fields:

{
  "status": "error",
  "message": "rule_type is required"
}

400 Bad Request - Invalid rule type:

{
  "status": "error",
  "message": "Invalid rule_type. Must be one of: unexpected_port, drift_detection, cert_expiry, weak_tls, ping_failed"
}

400 Bad Request - Invalid severity:

{
  "status": "error",
  "message": "Invalid severity. Must be one of: critical, warning, info"
}

Usage Examples:

# Create certificate expiry rule
curl -X POST http://localhost:5000/api/alerts/rules \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Cert Expiry Warning",
    "rule_type": "cert_expiry",
    "threshold": 30,
    "severity": "warning",
    "email_enabled": true
  }' \
  -b cookies.txt

# Create drift detection rule for specific config
curl -X POST http://localhost:5000/api/alerts/rules \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Production Drift Alert",
    "rule_type": "drift_detection",
    "threshold": 10,
    "severity": "critical",
    "config_file": "/app/configs/production.yaml",
    "email_enabled": true,
    "webhook_enabled": true
  }' \
  -b cookies.txt

Update Alert Rule

Update an existing alert rule.

Endpoint: PUT /api/alerts/rules/{rule_id}

Authentication: Required

Path Parameters:

Parameter Type Required Description
rule_id integer Yes Alert rule ID

Request Body:

{
  "name": "Updated Rule Name",
  "threshold": 60,
  "enabled": true,
  "email_enabled": true,
  "severity": "critical"
}

Note: All fields are optional. Only provided fields will be updated.

Success Response (200 OK):

{
  "status": "success",
  "message": "Alert rule updated successfully",
  "rule": {
    "id": 1,
    "name": "Updated Rule Name",
    "rule_type": "cert_expiry",
    "enabled": true,
    "threshold": 60,
    "email_enabled": true,
    "webhook_enabled": false,
    "severity": "critical",
    "filter_conditions": null,
    "config_file": "/app/configs/production.yaml",
    "created_at": "2025-11-01T10:00:00Z",
    "updated_at": "2025-11-18T10:00:00Z"
  }
}

Error Responses:

404 Not Found - Rule doesn't exist:

{
  "status": "error",
  "message": "Alert rule 1 not found"
}

400 Bad Request - Invalid severity:

{
  "status": "error",
  "message": "Invalid severity. Must be one of: critical, warning, info"
}

Usage Example:

# Disable a rule
curl -X PUT http://localhost:5000/api/alerts/rules/1 \
  -H "Content-Type: application/json" \
  -d '{"enabled":false}' \
  -b cookies.txt

# Update threshold and enable email
curl -X PUT http://localhost:5000/api/alerts/rules/1 \
  -H "Content-Type: application/json" \
  -d '{"threshold":15,"email_enabled":true}' \
  -b cookies.txt

Delete Alert Rule

Delete an alert rule. Associated alerts are also deleted via cascade.

Endpoint: DELETE /api/alerts/rules/{rule_id}

Authentication: Required

Path Parameters:

Parameter Type Required Description
rule_id integer Yes Alert rule ID

Success Response (200 OK):

{
  "status": "success",
  "message": "Alert rule 1 deleted successfully"
}

Error Responses:

404 Not Found - Rule doesn't exist:

{
  "status": "error",
  "message": "Alert rule 1 not found"
}

Usage Example:

curl -X DELETE http://localhost:5000/api/alerts/rules/1 \
  -b cookies.txt

Get Alert Statistics

Get alert statistics for a specified time period.

Endpoint: GET /api/alerts/stats

Authentication: Required

Query Parameters:

Parameter Type Required Default Description
days integer No 7 Number of days to look back (1-365)

Success Response (200 OK):

{
  "stats": {
    "total_alerts": 42,
    "unacknowledged_count": 5,
    "alerts_by_severity": {
      "critical": 3,
      "warning": 15,
      "info": 24
    },
    "alerts_by_type": {
      "cert_expiry": 10,
      "drift_detection": 8,
      "unexpected_port": 12,
      "weak_tls": 7,
      "ping_failed": 5
    },
    "date_range": {
      "start": "2025-11-11T10:00:00Z",
      "end": "2025-11-18T10:00:00Z",
      "days": 7
    }
  }
}

Usage Examples:

# Get stats for last 7 days
curl -X GET http://localhost:5000/api/alerts/stats \
  -b cookies.txt

# Get stats for last 30 days
curl -X GET "http://localhost:5000/api/alerts/stats?days=30" \
  -b cookies.txt

Health Check

Check API health status.

Endpoint: GET /api/alerts/health

Authentication: Not required

Success Response (200 OK):

{
  "status": "healthy",
  "api": "alerts",
  "version": "1.0.0-phase5"
}

Usage Example:

curl -X GET http://localhost:5000/api/alerts/health

Webhooks API

Manage webhook configurations for alert notifications with support for various authentication methods and delivery tracking.

List Webhooks

List all configured webhooks with pagination.

Endpoint: GET /api/webhooks

Authentication: Required

Query Parameters:

Parameter Type Required Default Description
page integer No 1 Page number (1-indexed)
per_page integer No 20 Items per page (1-100)
enabled boolean No - Filter by enabled status (true/false)

Success Response (200 OK):

{
  "webhooks": [
    {
      "id": 1,
      "name": "Slack Notifications",
      "url": "https://hooks.slack.com/services/XXX/YYY/ZZZ",
      "enabled": true,
      "auth_type": "none",
      "auth_token": null,
      "custom_headers": null,
      "alert_types": ["cert_expiry", "drift_detection"],
      "severity_filter": ["critical", "warning"],
      "timeout": 10,
      "retry_count": 3,
      "created_at": "2025-11-18T10:00:00Z",
      "updated_at": "2025-11-18T10:00:00Z"
    }
  ],
  "total": 1,
  "page": 1,
  "per_page": 20,
  "pages": 1
}

Usage Examples:

# List all webhooks
curl -X GET http://localhost:5000/api/webhooks \
  -b cookies.txt

# List only enabled webhooks
curl -X GET "http://localhost:5000/api/webhooks?enabled=true" \
  -b cookies.txt

Get Webhook

Get details for a specific webhook.

Endpoint: GET /api/webhooks/{id}

Authentication: Required

Path Parameters:

Parameter Type Required Description
id integer Yes Webhook ID

Success Response (200 OK):

{
  "webhook": {
    "id": 1,
    "name": "Slack Notifications",
    "url": "https://hooks.slack.com/services/XXX/YYY/ZZZ",
    "enabled": true,
    "auth_type": "bearer",
    "auth_token": "***ENCRYPTED***",
    "custom_headers": null,
    "alert_types": ["cert_expiry"],
    "severity_filter": ["critical"],
    "timeout": 10,
    "retry_count": 3,
    "created_at": "2025-11-18T10:00:00Z",
    "updated_at": "2025-11-18T10:00:00Z"
  }
}

Error Responses:

404 Not Found - Webhook doesn't exist:

{
  "status": "error",
  "message": "Webhook 1 not found"
}

Usage Example:

curl -X GET http://localhost:5000/api/webhooks/1 \
  -b cookies.txt

Create Webhook

Create a new webhook configuration.

Endpoint: POST /api/webhooks

Authentication: Required

Request Body:

{
  "name": "Slack Notifications",
  "url": "https://hooks.slack.com/services/XXX/YYY/ZZZ",
  "enabled": true,
  "auth_type": "bearer",
  "auth_token": "your-secret-token",
  "custom_headers": {
    "X-Custom-Header": "value"
  },
  "alert_types": ["cert_expiry", "drift_detection"],
  "severity_filter": ["critical", "warning"],
  "timeout": 10,
  "retry_count": 3
}

Request Body Fields:

Field Type Required Description
name string Yes Webhook name
url string Yes Webhook URL
enabled boolean No Whether webhook is enabled (default: true)
auth_type string No Authentication type: none, bearer, basic, custom (default: none)
auth_token string No Authentication token (encrypted when stored)
custom_headers object No JSON object with custom HTTP headers
alert_types array No Array of alert types to filter (empty = all types)
severity_filter array No Array of severities to filter (empty = all severities)
timeout integer No Request timeout in seconds (default: 10)
retry_count integer No Number of retry attempts (default: 3)

Success Response (201 Created):

{
  "status": "success",
  "message": "Webhook created successfully",
  "webhook": {
    "id": 1,
    "name": "Slack Notifications",
    "url": "https://hooks.slack.com/services/XXX/YYY/ZZZ",
    "enabled": true,
    "auth_type": "bearer",
    "alert_types": ["cert_expiry"],
    "severity_filter": ["critical"],
    "custom_headers": null,
    "timeout": 10,
    "retry_count": 3,
    "created_at": "2025-11-18T10:00:00Z"
  }
}

Error Responses:

400 Bad Request - Missing required fields:

{
  "status": "error",
  "message": "name is required"
}

400 Bad Request - Invalid auth type:

{
  "status": "error",
  "message": "Invalid auth_type. Must be one of: none, bearer, basic, custom"
}

Usage Examples:

# Create webhook with no authentication
curl -X POST http://localhost:5000/api/webhooks \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Slack Notifications",
    "url": "https://hooks.slack.com/services/XXX/YYY/ZZZ",
    "alert_types": ["cert_expiry", "drift_detection"],
    "severity_filter": ["critical"]
  }' \
  -b cookies.txt

# Create webhook with bearer token authentication
curl -X POST http://localhost:5000/api/webhooks \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Custom API",
    "url": "https://api.example.com/webhook",
    "auth_type": "bearer",
    "auth_token": "your-secret-token"
  }' \
  -b cookies.txt

Update Webhook

Update an existing webhook configuration.

Endpoint: PUT /api/webhooks/{id}

Authentication: Required

Path Parameters:

Parameter Type Required Description
id integer Yes Webhook ID

Request Body:

{
  "name": "Updated Name",
  "enabled": false,
  "timeout": 15
}

Note: All fields are optional. Only provided fields will be updated.

Success Response (200 OK):

{
  "status": "success",
  "message": "Webhook updated successfully",
  "webhook": {
    "id": 1,
    "name": "Updated Name",
    "url": "https://hooks.slack.com/services/XXX/YYY/ZZZ",
    "enabled": false,
    "auth_type": "none",
    "alert_types": ["cert_expiry"],
    "severity_filter": ["critical"],
    "custom_headers": null,
    "timeout": 15,
    "retry_count": 3,
    "updated_at": "2025-11-18T11:00:00Z"
  }
}

Error Responses:

404 Not Found - Webhook doesn't exist:

{
  "status": "error",
  "message": "Webhook 1 not found"
}

Usage Example:

# Disable a webhook
curl -X PUT http://localhost:5000/api/webhooks/1 \
  -H "Content-Type: application/json" \
  -d '{"enabled":false}' \
  -b cookies.txt

# Update timeout and retry count
curl -X PUT http://localhost:5000/api/webhooks/1 \
  -H "Content-Type: application/json" \
  -d '{"timeout":20,"retry_count":5}' \
  -b cookies.txt

Delete Webhook

Delete a webhook and all associated delivery logs.

Endpoint: DELETE /api/webhooks/{id}

Authentication: Required

Path Parameters:

Parameter Type Required Description
id integer Yes Webhook ID

Success Response (200 OK):

{
  "status": "success",
  "message": "Webhook 1 deleted successfully"
}

Error Responses:

404 Not Found - Webhook doesn't exist:

{
  "status": "error",
  "message": "Webhook 1 not found"
}

Usage Example:

curl -X DELETE http://localhost:5000/api/webhooks/1 \
  -b cookies.txt

Test Webhook

Send a test payload to a webhook to verify configuration.

Endpoint: POST /api/webhooks/{id}/test

Authentication: Required

Path Parameters:

Parameter Type Required Description
id integer Yes Webhook ID to test

Success Response (200 OK):

{
  "status": "success",
  "message": "HTTP 200",
  "status_code": 200,
  "response_body": "ok"
}

Error Response (failure to connect):

{
  "status": "error",
  "message": "Connection error: Failed to resolve hostname",
  "status_code": null
}

Test Payload Format:

{
  "event": "webhook.test",
  "message": "This is a test webhook from SneakyScanner",
  "timestamp": "2025-11-18T10:00:00Z",
  "webhook": {
    "id": 1,
    "name": "Slack Notifications"
  }
}

Usage Example:

curl -X POST http://localhost:5000/api/webhooks/1/test \
  -b cookies.txt

Get Webhook Delivery Logs

Get delivery history for a specific webhook.

Endpoint: GET /api/webhooks/{id}/logs

Authentication: Required

Path Parameters:

Parameter Type Required Description
id integer Yes Webhook ID

Query Parameters:

Parameter Type Required Default Description
page integer No 1 Page number (1-indexed)
per_page integer No 20 Items per page (1-100)
status string No - Filter by status (success/failed)

Success Response (200 OK):

{
  "webhook_id": 1,
  "webhook_name": "Slack Notifications",
  "logs": [
    {
      "id": 101,
      "alert_id": 42,
      "alert_type": "cert_expiry",
      "alert_message": "Certificate expires in 15 days",
      "status": "success",
      "response_code": 200,
      "response_body": "ok",
      "error_message": null,
      "attempt_number": 1,
      "delivered_at": "2025-11-18T10:30:00Z"
    },
    {
      "id": 100,
      "alert_id": 41,
      "alert_type": "drift_detection",
      "alert_message": "Port drift detected",
      "status": "failed",
      "response_code": null,
      "response_body": null,
      "error_message": "Request timeout after 10 seconds",
      "attempt_number": 3,
      "delivered_at": "2025-11-18T09:00:00Z"
    }
  ],
  "total": 2,
  "page": 1,
  "per_page": 20,
  "pages": 1
}

Error Responses:

404 Not Found - Webhook doesn't exist:

{
  "status": "error",
  "message": "Webhook 1 not found"
}

Usage Examples:

# Get all delivery logs
curl -X GET http://localhost:5000/api/webhooks/1/logs \
  -b cookies.txt

# Get only failed deliveries
curl -X GET "http://localhost:5000/api/webhooks/1/logs?status=failed" \
  -b cookies.txt

# Get page 2
curl -X GET "http://localhost:5000/api/webhooks/1/logs?page=2" \
  -b cookies.txt

Webhook Payload Format

When alerts are triggered, webhooks receive JSON payloads in this format:

{
  "event": "alert.created",
  "alert": {
    "id": 123,
    "type": "cert_expiry",
    "severity": "warning",
    "message": "Certificate for 192.168.1.10:443 expires in 15 days",
    "ip_address": "192.168.1.10",
    "port": 443,
    "acknowledged": false,
    "created_at": "2025-11-18T10:30:00Z"
  },
  "scan": {
    "id": 42,
    "title": "Production Network Scan",
    "timestamp": "2025-11-18T10:00:00Z",
    "status": "completed"
  },
  "rule": {
    "id": 3,
    "name": "Certificate Expiry Warning",
    "type": "cert_expiry",
    "threshold": 30
  }
}

Authentication Types

None:

  • No authentication headers added

Bearer Token:

  • Adds Authorization: Bearer <token> header
  • Token is encrypted in database

Basic Authentication:

  • Format: username:password in auth_token field
  • Automatically converts to HTTP Basic Auth
  • Credentials encrypted in database

Custom Headers:

  • Define any custom HTTP headers
  • Useful for API keys or custom authentication schemes
  • Example:
{
  "X-API-Key": "your-api-key",
  "X-Custom-Header": "value"
}

Retry Logic

Failed webhook deliveries are automatically retried with exponential backoff:

  • Attempt 1: Immediate
  • Attempt 2: After 2 seconds
  • Attempt 3: After 4 seconds
  • Attempt 4: After 8 seconds
  • Maximum delay: 60 seconds

Retry count is configurable per webhook (0-5 attempts).

Health Check

Check API health status.

Endpoint: GET /api/webhooks/health

Authentication: Not required

Success Response (200 OK):

{
  "status": "healthy",
  "api": "webhooks",
  "version": "1.0.0-phase5"
}

Usage Example:

curl -X GET http://localhost:5000/api/webhooks/health

Error Handling

Error Response Format

All error responses follow a consistent JSON format:

{
  "error": "Brief error type",
  "message": "Detailed error message for debugging"
}

Content Negotiation

The API supports content negotiation based on the request:

  • API Requests (Accept: application/json or /api/* path): Returns JSON errors
  • Web Requests (Accept: text/html): Returns HTML error pages

Example:

# JSON error response
curl -X GET http://localhost:5000/api/scans/999 \
  -H "Accept: application/json" \
  -b cookies.txt

# HTML error page
curl -X GET http://localhost:5000/scans/999 \
  -H "Accept: text/html" \
  -b cookies.txt

Request ID Tracking

Every request receives a unique request ID for tracking and debugging:

Response Headers:

X-Request-ID: a1b2c3d4
X-Request-Duration-Ms: 125

Check application logs for detailed error information using the request ID:

2025-11-14 10:30:15 INFO [a1b2c3d4] GET /api/scans 200 125ms

Status Codes

Success Codes

Code Meaning Usage
200 OK Successful GET, PUT, DELETE requests
201 Created Successful POST request that creates a resource
302 Found Redirect (used for logout, login success)

Client Error Codes

Code Meaning Usage
400 Bad Request Invalid request parameters or body
401 Unauthorized Authentication required or failed
403 Forbidden Authenticated but not authorized
404 Not Found Resource doesn't exist
405 Method Not Allowed HTTP method not supported for endpoint

Server Error Codes

Code Meaning Usage
500 Internal Server Error Unexpected server error

Request/Response Examples

Complete Workflow: Trigger and Monitor Scan

#!/bin/bash

# 1. Login and save session
curl -X POST http://localhost:5000/auth/login \
  -H "Content-Type: application/json" \
  -d '{"password":"yourpassword"}' \
  -c cookies.txt

# 2. Trigger a new scan
RESPONSE=$(curl -s -X POST http://localhost:5000/api/scans \
  -H "Content-Type: application/json" \
  -d '{"config_file":"/app/configs/production.yaml"}' \
  -b cookies.txt)

# Extract scan ID from response
SCAN_ID=$(echo $RESPONSE | jq -r '.scan_id')
echo "Scan ID: $SCAN_ID"

# 3. Poll status every 5 seconds until complete
while true; do
  STATUS=$(curl -s -X GET http://localhost:5000/api/scans/$SCAN_ID/status \
    -b cookies.txt | jq -r '.status')

  echo "Status: $STATUS"

  if [ "$STATUS" == "completed" ] || [ "$STATUS" == "failed" ]; then
    break
  fi

  sleep 5
done

# 4. Get full scan results
curl -X GET http://localhost:5000/api/scans/$SCAN_ID \
  -b cookies.txt | jq '.'

# 5. Logout
curl -X GET http://localhost:5000/auth/logout \
  -b cookies.txt

Pagination Example

#!/bin/bash

# Get total number of scans
TOTAL=$(curl -s -X GET "http://localhost:5000/api/scans?per_page=1" \
  -b cookies.txt | jq -r '.total')

echo "Total scans: $TOTAL"

# Calculate number of pages (50 items per page)
PER_PAGE=50
PAGES=$(( ($TOTAL + $PER_PAGE - 1) / $PER_PAGE ))

echo "Total pages: $PAGES"

# Fetch all pages
for PAGE in $(seq 1 $PAGES); do
  echo "Fetching page $PAGE..."
  curl -s -X GET "http://localhost:5000/api/scans?page=$PAGE&per_page=$PER_PAGE" \
    -b cookies.txt | jq '.scans[] | {id, timestamp, title, status}'
done

Filter by Status

# Get all running scans
curl -X GET "http://localhost:5000/api/scans?status=running" \
  -b cookies.txt | jq '.scans[] | {id, title, started_at}'

# Get all failed scans
curl -X GET "http://localhost:5000/api/scans?status=failed" \
  -b cookies.txt | jq '.scans[] | {id, title, error_message}'

# Get all completed scans from last 24 hours
curl -X GET "http://localhost:5000/api/scans?status=completed" \
  -b cookies.txt | jq '.scans[] | select(.completed_at > (now - 86400 | todate)) | {id, title, duration}'

Rate Limiting

Currently no rate limiting is implemented. For production deployments, consider:

  • Adding nginx rate limiting
  • Implementing application-level rate limiting with Flask-Limiter
  • Setting connection limits in Gunicorn configuration

Security Considerations

Authentication

  • All API endpoints (except /auth/login and /api/settings/health) require authentication
  • Session cookies are httpOnly and secure (in production with HTTPS)
  • Passwords are hashed with bcrypt (cost factor 12)
  • Sensitive settings values are encrypted at rest

CORS

CORS is configured via environment variable CORS_ORIGINS. Default: * (allow all).

For production, set to specific origins:

CORS_ORIGINS=https://scanner.example.com,https://admin.example.com

HTTPS

For production deployments:

  1. Use HTTPS (TLS/SSL) for all requests
  2. Set SESSION_COOKIE_SECURE=True in Flask config
  3. Consider using a reverse proxy (nginx) with SSL termination

Input Validation

All inputs are validated:

  • Config file paths are checked for existence and valid YAML
  • Pagination parameters are sanitized (positive integers, max per_page: 100)
  • Scan IDs are validated as integers
  • Setting values are type-checked

Versioning

Current Version: 5.0 (Phase 5)

API versioning will be implemented in future phases. For now, the API is considered stable for Phase 5 features.

Recent Breaking Changes:

  • Phase 2 → Phase 3: Added scan comparison endpoint, schedules API
  • Phase 3 → Phase 4: Added configs API, stats API, multiple settings endpoints
  • Phase 4 → Phase 5: Full alerts API implementation with filtering, acknowledgment, and statistics

Upcoming Changes:

  • Phase 6+: API versioning with backward compatibility guarantees

API Summary

Implemented APIs (Phase 5)

  • Authentication API - Login, logout, setup
  • Scans API - Full CRUD, status polling, comparison
  • Configs API - File management, CIDR generation, YAML upload
  • Schedules API - CRUD operations, manual triggering, APScheduler integration
  • Stats API - Trends, summaries, historical data
  • Settings API - Application configuration, password management
  • Alerts API - Full implementation with filtering, acknowledgment, rules management, and statistics
  • Webhooks API - Webhook management, delivery tracking, authentication support, retry logic

Endpoint Count

  • Total endpoints: 65+
  • Authenticated endpoints: 60+
  • Public endpoints: 5 (login, setup, health checks)

Support

For issues, questions, or feature requests:


Last Updated: 2025-11-18 Phase: 5 - Alerts Management Next Update: Phase 6 - Future Enhancements