REST API Reference
FlowGuard Lite provides a clean, JSON-based REST API to inspect traffic analytics, query anomalies, manage configurations, and extract firewall rules.
1. System Endpoints
GET /api/health
Retrieves daemon health status, collector statistics, and queue depth indicators.
- Response Status:
200 OK - Example Response:
{ "status": "OK", "healthy": true, "environment": "production", "timestamp": "2026-07-09T15:28:33Z", "version": "0.1.0", "collector": { "packets_received": 145028, "packets_dropped": 0, "decode_errors": 0, "queue_depth": 14, "sources": [ { "kind": "netflow", "id": "netflow", "enabled": true, "status": "listening", "port": 2055, "packets": 120000 }, { "kind": "unifi_syslog", "id": "unifi_syslog", "enabled": true, "status": "listening", "port": 5514, "packets": 420, "drops": 1, "decode_errors": 2 } ] } }
Collector source health uses bounded labels (kind, id) rather than per-client, per-exporter, or sender-provided labels. UniFi syslog source counters report parsed packet intake, drops, and parse errors; retained UniFi event evidence is exposed through the UniFi security event endpoints. Exporter IPs remain available through /api/exporters.
GET /api/auth/status
Returns local access-control state.
- Response Status:
200 OK - Example Response:
{ "authenticated": false, "setup_required": true }
POST /api/auth/setup
Creates the initial local admin password. This endpoint only works while no admin password hash is configured.
- Request Body:
{ "password": "minimum 10 characters" } - Response Status:
200 OK - Security: Stores only a PBKDF2-SHA256 password hash and sets an
HttpOnly,SameSite=Laxsession cookie.
POST /api/auth/login
Authenticates the local admin password and creates a browser session.
- Request Body:
{ "password": "admin password" } - Response Status:
200 OK - Failure Responses:
401 Unauthorizedfor invalid credentials,429 Too Many Requestsafter repeated failures.
POST /api/auth/logout
Invalidates the current browser session cookie.
- Response Status:
200 OK
GET /api/exporters
Lists all active exporters (routers/gateways) streaming NetFlow or sFlow telemetry to the daemon.
- Response Status:
200 OK - Example Response:
[ { "ip": "192.168.1.1", "last_seen": "2026-07-04T14:40:00Z", "packet_count": 12402 } ]
2. Analytics & Devices
GET /api/devices
Lists all discovered local network devices with their hostnames, custom labels, and risk indicators.
- Response Status:
200 OK - Example Response:
[ { "ip": "192.168.1.50", "mac": "00:11:22:33:44:55", "hostname": "NAS-Server", "label": "Storage", "first_seen": "2026-07-04T10:00:00Z", "last_seen": "2026-07-04T14:40:00Z" } ]
GET /api/risk/devices
Lists internal devices ranked by their calculated threat risk scores (0 - 100).
- Response Status:
200 OK - Example Response:
[ { "ip": "192.168.1.50", "label": "Storage", "risk_score": 85, "risk_level": "high" } ]
Overview dashboard data composition
The default Overview dashboard uses bounded summary and stats endpoints.
- Visibility status:
GET /api/security/summaryandGET /api/security/timeline. - Network stats:
GET /api/stats/protocols,GET /api/stats/top-devices,GET /api/stats/heatmap, plusGET /api/traffic/timeseries. - Flow explorer:
GET /api/traffic/recordsreturns retained aggregate rows for bounded operator filtering. It does not expose raw packets or unbounded raw flow storage. - Security: Secret settings are not displayed in the dashboard; only configuration presence is shown.
GET /api/security/summary
Returns active alert counts by severity, max risk score, elevated device count, risk distribution, detector coverage, DDoS thresholds, collector counters, top risk devices, and recent high-severity alerts.
GET /api/security/timeline
Returns alert count buckets for the selected time range.
Uses start, end, and bucket_seconds query parameters with the same 7-day maximum range as /api/traffic/timeseries.
GET /api/stats/protocols
Returns protocol byte distribution for a bounded range.
Uses the same start, end, and limit query parameters as /api/top/sources.
GET /api/stats/top-devices
Returns known devices ranked by combined source and destination byte volume for a bounded range.
Uses the same start, end, and limit query parameters as /api/top/sources.
GET /api/stats/heatmap
Returns hour-of-day traffic cells for top devices in a bounded range.
Uses the same start, end, and limit query parameters as /api/top/sources; limit is capped at 20 devices.
GET /api/stats/collector-health
Returns bounded in-memory collector health samples for Overview sparklines.
- Query Parameters:
limit(Optional, integer): Defaults to120; capped at240.
- Example Response:
[ { "timestamp": "2026-07-08T15:40:00Z", "packets_received": 145028, "packets_dropped": 0, "decode_errors": 0, "queue_depth": 14 } ]
GET /api/traffic/timeseries
Returns bounded aggregate traffic counters for network charts.
- Query Parameters:
start(Optional, RFC3339): Defaults to one hour beforeend.end(Optional, RFC3339): Defaults to now.bucket_seconds(Optional): One of60,300,900, or3600. Defaults to300.
- Limits: The maximum query range is 7 days.
- Response Status:
200 OK - Example Response:
[ { "timestamp": "2026-07-04T14:00:00Z", "bytes": 15432000, "packets": 12402, "flows": 384 } ]
GET /api/traffic/records
Returns retained aggregate rows for operator search/filter workflows. Each row is a bounded rollup from flow_aggregates, not a raw packet or indefinite raw flow record. Collector identity is reported separately from exporter_ip so NetFlow/sFlow and passive capture sources can coexist without ambiguity.
- Query Parameters:
start(Optional, RFC3339): Defaults to one hour beforeend.end(Optional, RFC3339): Defaults to now.limit(Optional, integer): Defaults to10; capped by API pagination.q(Optional, string): Case-insensitive match against source or destination IP; capped at 128 characters.protocol(Optional, integer): IP protocol number,0-255.dst_port(Optional, integer): Destination port,0-65535.
- Limits: The maximum query range is 7 days.
- Example Response:
[ { "timestamp": "2026-07-04T14:00:00Z", "collector_kind": "netflow", "collector_id": "unifi-gateway", "src_ip": "192.168.30.150", "dst_ip": "8.8.8.8", "dst_port": 53, "protocol": 17, "bytes": 1200, "packets": 12, "flows": 2 } ]
GET /api/top/sources
Returns the top source IP addresses by byte volume for a bounded time range.
- Query Parameters:
start(Optional, RFC3339): Defaults to one hour beforeend.end(Optional, RFC3339): Defaults to now.limit(Optional, integer): Defaults to10.
- Limits: The maximum query range is 7 days.
GET /api/top/destinations
Returns the top destination IP addresses by byte volume for a bounded time range.
Uses the same query parameters and 7-day maximum range as /api/top/sources.
GET /api/top/ports
Returns the top destination ports by byte volume for a bounded time range.
Uses the same query parameters and 7-day maximum range as /api/top/sources.
GET /api/top/protocols
Returns the top transport protocol numbers by byte volume for a bounded time range.
Uses the same query parameters and 7-day maximum range as /api/top/sources.
- Example Response:
[ { "key": "6", "bytes": 328780000, "packets": 84200, "flows": 1260 } ]
3. Anomalies & Audit Logs
GET /api/anomalies
Lists all flagged anomalies, baseline breaches, or volumetric DDoS detections.
- Query Parameters:
limit(Optional, integer): Default50. Limit results returned.
- Response Status:
200 OK - Example Response:
[ { "id": 42, "ip": "192.168.1.50", "destination_ip": "192.168.1.25", "type": "NEW_INTERNAL_COMMUNICATION", "description": "what happened: device contacted internal peer 192.168.1.25 after its east-west peer set was learned; why unusual: this local-to-local communication pattern was not present in the learned internal peer baseline...", "severity": "medium", "status": "active", "created_at": "2026-07-04T14:38:00Z", "updated_at": "2026-07-04T14:38:00Z" } ]
destination_ip is omitted or empty when a detector does not have one specific destination. When present, ip/subnet policies can match either the source ip or the structured destination_ip.
GET /api/audit-logs
Lists security audit entries documenting configuration modifications and threat triage responses.
- Response Status:
200 OK - Example Response:
[ { "timestamp": "2026-07-04T14:30:00Z", "action": "settings_updated", "details": "Local subnets range modified to: 192.168.1.0/24" } ]
4. Settings Configuration
GET /api/settings
Returns the active configuration schema.
- Response Status:
200 OK - Example Response:
{ "port": "8080", "netflow_port": 2055, "sflow_port": 6343, "capture_interface": "", "capture_bpf_filter": "ip or ip6", "capture_promiscuous": false, "unifi_syslog_enabled": false, "unifi_syslog_port": 5514, "unifi_syslog_allowed_ips": [ "192.168.1.1" ], "storage_backend": "sqlite", "local_subnets": [ "192.168.1.0/24" ], "slack_webhook_url": "https://example.com/slack-webhook", "webhook_url": "https://automation.example.local/flowguard-alerts", "webhook_format": "generic", "webhook_headers": { "Authorization": "******" }, "first_run_completed": true, "retention_days": 7, "disabled_anomaly_types": [ "NEW_PORT" ], "muted_anomaly_subnets": [ "192.168.50.0/24" ], "notify_allowed_subnets": [ "192.168.10.0/24" ], "notify_suppressed_types": [ "BEACONING" ], "new_destination_min_history_buckets": 12, "beacon_min_observations": 12, "beacon_min_interval_seconds": 90, "traffic_spike_min_packets": 2500, "traffic_spike_min_bytes": 1048576, "ddos_threshold_pps": 5000, "ddos_threshold_bps": 10485760, "ddos_threshold_fps": 1000, "syn_flood_threshold_pps": 1000, "udp_flood_threshold_pps": 3000, "icmp_flood_threshold_pps": 500, "suricata_eve_path": "/var/log/suricata/eve.json", "admin_password": "" }
POST /api/settings
Updates the configuration keys and saves them to config.yaml on disk.
- Request Body JSON Schema: (Same as GET response)
- Response Status:
200 OK(Returns the updated config) - Collector validation:
netflow_portandsflow_portaccept0to disable those listeners. Enabled UDP collector ports must not conflict. UniFi SIEM/syslog usesunifi_syslog_enabled,unifi_syslog_port, and optionalunifi_syslog_allowed_ips; it is distinct from NetFlow/IPFIX, uses bounded datagram/queue handling, and changes require a daemon restart. - Passive capture validation:
capture_interfaceis optional and enables capture when non-empty. An enabled interface requires a non-emptycapture_bpf_filter; interface and filter values are length-bounded and reject null/control line breaks. Capture changes require a daemon restart. - Detection/noise validation: anomaly type lists accept known alert identifiers only.
muted_anomaly_subnetsandnotify_allowed_subnetsmust be CIDR ranges. Detector sensitivity thresholds must be positive and bounded. Notification allow/suppress controls affect outbound dispatch only; stored anomalies remain available unless the detector is disabled or muted.
5. Policy Configuration
GET /api/policies
Lists all active policies.
- Response Status:
200 OK - Example Response:
[ { "id": 1, "name": "Silence Port Scans", "scope": "alert_type", "target": "port_scan", "severity_threshold": "medium", "suppressed": true, "cooldown_seconds": 60, "quiet_hours_start": "22:00", "quiet_hours_end": "06:00", "notification_channels": ["slack", "telegram"], "created_at": "2026-07-05T14:40:00Z", "updated_at": "2026-07-05T14:40:00Z" } ]
POST /api/policies
Creates a new policy.
- Request Body JSON:
{ "name": "Silence Port Scans", "scope": "alert_type", "target": "port_scan", "severity_threshold": "medium", "suppressed": true, "cooldown_seconds": 60, "quiet_hours_start": "22:00", "quiet_hours_end": "06:00", "notification_channels": ["slack", "telegram"] } - Response Status:
200 OK(Returns the created policy object with populatedid,created_atandupdated_at)
To suppress all anomaly types for one verified noisy device, create an exact-IP policy:
{
"name": "Authorized infrastructure scanner",
"scope": "ip",
"target": "192.168.10.25",
"severity_threshold": "",
"suppressed": true,
"cooldown_seconds": 0,
"quiet_hours_start": "",
"quiet_hours_end": "",
"notification_channels": []
}
Matching anomalies remain persisted with status silenced. Policy precedence is ip > subnet > alert_type > global; the newest policy wins when scopes have equal precedence. Equivalent textual forms of the same IPv6 address are treated as one address.
To suppress a verified benign destination, use the same ip scope with the destination address as target. The policy matches anomalies whose structured destination_ip equals that address while leaving unrelated destinations active.
PUT /api/policies/{id}
Updates an existing policy.
- Request Body JSON: (Same as POST payload, optionally including fields to edit)
- Response Status:
200 OK(Returns the updated policy object) - Failure Response:
400 Bad Requestif payload is invalid (e.g. invalid quiet hours format, missing name, or invalid target format).
DELETE /api/policies/{id}
Deletes a policy by its ID.
- Response Status:
200 OK - Example Response:
{ "status": "deleted" }