Complete reference documentation for all WarDragon Analytics REST API endpoints.
Base URL: http://localhost:8090 (default)
Format: JSON
Authentication: Optional (set AUTH_ENABLED=true in .env - see SECURITY.md)
- Overview
- Core Endpoints
- Kit Admin Endpoints
- Pattern Detection Endpoints
- Security Pattern Endpoints
- AI Assistant Endpoints
- Error Codes
- Data Models
- Integration Examples
WarDragon Analytics provides a REST API for querying drone surveillance data aggregated from multiple WarDragon kits. The API is built with FastAPI and returns JSON responses.
API Version: 1.0.0
Key Features:
- Real-time drone track queries
- FPV signal detection data
- Multi-kit aggregation
- Pattern detection and anomaly identification
- CSV export for offline analysis
- Kit health monitoring
Check if the API and database are available.
Endpoint: GET /health
Use Case: Container healthcheck, monitoring, uptime checks
Parameters: None
Response:
{
"status": "healthy"
}Status Codes:
200 OK- Service is healthy503 Service Unavailable- Database connection failed
Example:
curl http://localhost:8090/healthQuery information about configured WarDragon kits.
Endpoint: GET /api/kits
Use Case: Get kit status, monitor kit health, list available kits
Parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
kit_id |
string | No | Filter by specific kit ID |
Response:
{
"kits": [
{
"kit_id": "kit-alpha",
"name": "Alpha Kit",
"location": "Building A - Rooftop",
"api_url": "http://192.168.1.100:8088",
"last_seen": "2026-01-20T15:30:00Z",
"status": "online",
"created_at": "2026-01-15T10:00:00Z"
}
],
"count": 1
}Kit Status Values:
online- Last seen < 30 seconds agostale- Last seen 30-120 seconds agooffline- Last seen > 120 seconds agounknown- Never seen or no data
Status Codes:
200 OK- Success500 Internal Server Error- Database error
Example:
# List all kits
curl http://localhost:8090/api/kits
# Get specific kit
curl "http://localhost:8090/api/kits?kit_id=kit-alpha"Query drone and aircraft detections with time-based and attribute filters.
Endpoint: GET /api/drones
Use Case: Retrieve drone tracks for visualization, analysis, or export
Parameters:
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
time_range |
string | No | 1h |
Time range: 1h, 24h, 7d, or custom:START,END |
kit_id |
string | No | - | Filter by kit ID (comma-separated for multiple) |
rid_make |
string | No | - | Filter by manufacturer (e.g., DJI, Autel) |
track_type |
string | No | - | Filter by type: drone or aircraft |
limit |
integer | No | 1000 |
Maximum results (max 10,000) |
deduplicate |
boolean | No | true |
Return only latest detection per drone_id |
Time Range Formats:
1h- Last 1 hour24h- Last 24 hours7d- Last 7 dayscustom:2026-01-20T10:00:00,2026-01-20T12:00:00- Custom ISO timestamps
Response:
{
"drones": [
{
"time": "2026-01-20T15:30:00Z",
"kit_id": "kit-alpha",
"drone_id": "DJI-1234567890ABCDEF",
"lat": 37.7749,
"lon": -122.4194,
"alt": 120.5,
"speed": 15.2,
"heading": 180.0,
"pilot_lat": 37.7750,
"pilot_lon": -122.4190,
"home_lat": 37.7751,
"home_lon": -122.4191,
"mac": "AA:BB:CC:DD:EE:FF",
"rssi": -65,
"freq": 2412.0,
"ua_type": "multirotor",
"operator_id": "OP12345678",
"caa_id": null,
"rid_make": "DJI",
"rid_model": "Mavic 3",
"rid_source": "BLE",
"track_type": "drone"
}
],
"count": 1,
"total_detections": 15,
"time_range": {
"start": "2026-01-20T14:30:00Z",
"end": "2026-01-20T15:30:00Z"
}
}Status Codes:
200 OK- Success500 Internal Server Error- Database error
Example:
# Last hour of all drones
curl http://localhost:8090/api/drones
# DJI drones only, last 24 hours
curl "http://localhost:8090/api/drones?time_range=24h&rid_make=DJI"
# Specific kit, last 7 days
curl "http://localhost:8090/api/drones?time_range=7d&kit_id=kit-alpha"
# Multiple kits
curl "http://localhost:8090/api/drones?kit_id=kit-alpha,kit-bravo"
# Custom time range
curl "http://localhost:8090/api/drones?time_range=custom:2026-01-20T10:00:00,2026-01-20T12:00:00"Get the flight path history for a specific drone.
Endpoint: GET /api/drones/{drone_id}/track
Use Case: Draw flight path polylines on a map, analyze movement patterns
Path Parameters:
| Parameter | Type | Description |
|---|---|---|
drone_id |
string | The drone's unique identifier |
Query Parameters:
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
time_range |
string | No | 1h |
Time range: 1h, 24h, 7d, or custom:START,END |
limit |
integer | No | 500 |
Maximum track points (max 2,000) |
Response:
{
"drone_id": "DJI-1234567890ABCDEF",
"track": [
{
"time": "2026-01-20T15:00:00Z",
"kit_id": "kit-alpha",
"lat": 37.7749,
"lon": -122.4194,
"alt": 50.0,
"speed": 5.2,
"heading": 90.0,
"rssi": -65
},
{
"time": "2026-01-20T15:05:00Z",
"kit_id": "kit-alpha",
"lat": 37.7755,
"lon": -122.4180,
"alt": 75.0,
"speed": 12.5,
"heading": 45.0,
"rssi": -62
}
],
"point_count": 2,
"time_range": {
"start": "2026-01-20T14:30:00Z",
"end": "2026-01-20T15:30:00Z"
}
}Status Codes:
200 OK- Success500 Internal Server Error- Database error
Example:
# Get track for last hour
curl "http://localhost:8090/api/drones/DJI-1234567890ABCDEF/track"
# Get track for last 24 hours
curl "http://localhost:8090/api/drones/DJI-1234567890ABCDEF/track?time_range=24h"
# Get track with more points
curl "http://localhost:8090/api/drones/DJI-1234567890ABCDEF/track?limit=1000"Query FPV and RF signal detections (5.8GHz analog, DJI, etc.).
Endpoint: GET /api/signals
Use Case: Analyze FPV signal activity, frequency usage, signal strength
Parameters:
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
time_range |
string | No | 1h |
Time range: 1h, 24h, 7d, or custom:START,END |
kit_id |
string | No | - | Filter by kit ID (comma-separated) |
detection_type |
string | No | - | Filter by type: analog or dji |
limit |
integer | No | 1000 |
Maximum results (max 10,000) |
Response:
{
"signals": [
{
"time": "2026-01-20T15:30:00Z",
"kit_id": "kit-alpha",
"freq_mhz": 5800.0,
"power_dbm": 0.752,
"bandwidth_mhz": 10.0,
"lat": 37.7749,
"lon": -122.4194,
"alt": 10.0,
"detection_type": "analog",
"pal_conf": 85.0,
"ntsc_conf": 12.0,
"source": "suscli",
"signal_type": "fpv"
}
],
"count": 1,
"time_range": "1h"
}Response Fields:
time- Detection timestamp (ISO 8601)kit_id- Kit that detected the signalfreq_mhz- Center frequency in MHzpower_dbm- Linear signal power (0-1 scale, higher = stronger). Note: field name is historical; actual values are NOT dBmbandwidth_mhz- Signal bandwidth in MHzlat,lon,alt- Kit GPS position at detection time (may be 0 if no GPS lock)detection_type- Signal classification (see below)pal_conf- PAL video format confidence (0-100%)ntsc_conf- NTSC video format confidence (0-100%)source- Detection source (e.g., "suscli")signal_type- General signal category
Detection Types:
analog- 5.8GHz analog FPV videodji_digital- DJI digital FPV (OcuSync)
Status Codes:
200 OK- Success500 Internal Server Error- Database error
Example:
# All signals, last hour
curl http://localhost:8090/api/signals
# Analog FPV detections, last 24 hours
curl "http://localhost:8090/api/signals?time_range=24h&detection_type=analog"
# DJI signals from specific kit
curl "http://localhost:8090/api/signals?detection_type=dji&kit_id=kit-alpha"Export drone tracks to CSV format for offline analysis.
Endpoint: GET /api/export/csv
Use Case: Download data for Excel, spreadsheet analysis, or archival
Parameters:
Same as /api/drones endpoint (see Drone Tracks)
Response: CSV file download
Content-Type: text/csv
Filename: wardragon_analytics_YYYYMMDD_HHMMSS.csv
CSV Columns:
time,kit_id,drone_id,lat,lon,alt,speed,heading,pilot_lat,pilot_lon,home_lat,home_lon,mac,rssi,freq,ua_type,operator_id,caa_id,rid_make,rid_model,rid_source,track_type
Status Codes:
200 OK- Success (returns CSV)500 Internal Server Error- Database or export error
Example:
# Export last 24 hours to CSV
curl -o drones.csv "http://localhost:8090/api/export/csv?time_range=24h"
# Export specific kit, last 7 days
curl -o alpha_7d.csv "http://localhost:8090/api/export/csv?time_range=7d&kit_id=kit-alpha"
# Export DJI drones only
curl -o dji_drones.csv "http://localhost:8090/api/export/csv?rid_make=DJI"Administrative endpoints for managing WarDragon kit configurations.
Add a new kit to the system.
Endpoint: POST /api/admin/kits
Use Case: Register a new WarDragon kit for polling
Request Body:
{
"api_url": "http://192.168.1.100:8088",
"name": "Field Kit Alpha",
"location": "Building A - Rooftop",
"enabled": true
}| Field | Type | Required | Description |
|---|---|---|---|
api_url |
string | Yes | Base URL for DragonSync API |
name |
string | No | Human-readable kit name |
location |
string | No | Physical location description |
enabled |
boolean | No | Whether to poll this kit (default: true) |
Response:
{
"success": true,
"kit_id": "kit-192-168-1-100",
"message": "Kit created successfully. Connection test passed.",
"connection_test": {
"success": true,
"kit_id": "wardragon-abc123",
"message": "Successfully connected to kit",
"response_time_ms": 45.2
}
}Status Codes:
200 OK- Kit created successfully409 Conflict- Kit already exists503 Service Unavailable- Database unavailable
Update an existing kit's configuration.
Endpoint: PUT /api/admin/kits/{kit_id}
Path Parameters:
| Parameter | Type | Description |
|---|---|---|
kit_id |
string | The kit's unique identifier |
Request Body:
{
"name": "Updated Kit Name",
"location": "New Location",
"enabled": false
}All fields are optional. Only provided fields will be updated.
Response:
{
"success": true,
"message": "Kit updated successfully",
"kit_id": "kit-alpha"
}Status Codes:
200 OK- Kit updated404 Not Found- Kit not found503 Service Unavailable- Database unavailable
Remove a kit from the system.
Endpoint: DELETE /api/admin/kits/{kit_id}
Path Parameters:
| Parameter | Type | Description |
|---|---|---|
kit_id |
string | The kit's unique identifier |
Query Parameters:
| Parameter | Type | Default | Description |
|---|---|---|---|
delete_data |
boolean | false |
Also delete all drone/signal data from this kit |
Response:
{
"success": true,
"message": "Kit kit-alpha deleted successfully",
"kit_id": "kit-alpha",
"deleted_data": {
"drones": 1523,
"signals": 456,
"health_records": 2890
}
}Status Codes:
200 OK- Kit deleted404 Not Found- Kit not found503 Service Unavailable- Database unavailable
Test connectivity to a kit's API without adding it.
Endpoint: POST /api/admin/kits/test
Query Parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
api_url |
string | Yes | API URL to test |
Response:
{
"success": true,
"kit_id": "wardragon-abc123",
"message": "Successfully connected to kit",
"response_time_ms": 45.2
}Test Existing Kit: POST /api/admin/kits/{kit_id}/test
Tests an existing kit's connectivity using its stored URL.
Check kit configuration and polling status.
Endpoint: GET /api/admin/kits/reload-status
Response:
{
"total_kits": 3,
"enabled_kits": 2,
"online_kits": 2,
"kits": [
{
"kit_id": "kit-alpha",
"name": "Alpha Kit",
"api_url": "http://192.168.1.100:8088",
"status": "online",
"enabled": true,
"last_seen": "2026-01-20T15:30:00Z"
}
]
}Advanced intelligence endpoints for tactical operations and threat detection.
Find drones that have been detected multiple times (surveillance pattern detection).
Endpoint: GET /api/patterns/repeated-drones
Use Case: Identify drones repeatedly visiting an area (surveillance, stalking, reconnaissance)
Parameters:
| Parameter | Type | Required | Default | Range | Description |
|---|---|---|---|---|---|
time_window_hours |
integer | No | 24 |
1-168 | Time window for analysis (hours) |
min_appearances |
integer | No | 2 |
≥2 | Minimum number of appearances |
Response:
{
"repeated_drones": [
{
"drone_id": "DJI-ABCD1234",
"first_seen": "2026-01-19T10:00:00Z",
"last_seen": "2026-01-20T15:30:00Z",
"appearance_count": 5,
"locations": [
{
"lat": 37.7749,
"lon": -122.4194,
"kit_id": "kit-alpha",
"timestamp": "2026-01-19T10:00:00Z"
},
{
"lat": 37.7750,
"lon": -122.4195,
"kit_id": "kit-alpha",
"timestamp": "2026-01-19T14:30:00Z"
}
]
}
],
"count": 1,
"time_window_hours": 24,
"min_appearances": 2
}Status Codes:
200 OK- Success422 Unprocessable Entity- Invalid parameters500 Internal Server Error- Database error503 Service Unavailable- Database unavailable
Example:
# Last 24 hours, 2+ appearances
curl http://localhost:8090/api/patterns/repeated-drones
# Last 48 hours, 3+ appearances
curl "http://localhost:8090/api/patterns/repeated-drones?time_window_hours=48&min_appearances=3"
# Last week
curl "http://localhost:8090/api/patterns/repeated-drones?time_window_hours=168"Detect groups of drones flying together (swarm detection, coordinated operations).
Endpoint: GET /api/patterns/coordinated
Use Case: Identify drone swarms, coordinated attacks, or synchronized operations
Parameters:
| Parameter | Type | Required | Default | Range | Description |
|---|---|---|---|---|---|
time_window_minutes |
integer | No | 60 |
1-1440 | Time window for grouping (minutes) |
distance_threshold_m |
integer | No | 500 |
≥10 | Maximum distance between drones (meters) |
Response:
{
"coordinated_groups": [
{
"group_id": 1,
"drone_count": 4,
"drones": [
{
"drone_id": "DJI-DRONE1",
"lat": 37.7749,
"lon": -122.4194,
"timestamp": "2026-01-20T15:30:00Z",
"kit_id": "kit-alpha",
"rid_make": "DJI"
},
{
"drone_id": "DJI-DRONE2",
"lat": 37.7750,
"lon": -122.4195,
"timestamp": "2026-01-20T15:30:05Z",
"kit_id": "kit-alpha",
"rid_make": "DJI"
}
],
"correlation_score": "high"
}
],
"count": 1,
"time_window_minutes": 60,
"distance_threshold_m": 500
}Correlation Score:
high- 5+ drones in groupmedium- 3-4 drones in grouplow- 2 drones in group
Algorithm: DBSCAN-style clustering using time and spatial proximity
Status Codes:
200 OK- Success422 Unprocessable Entity- Invalid parameters500 Internal Server Error- Database error503 Service Unavailable- Database unavailable
Example:
# Last hour, 500m grouping
curl http://localhost:8090/api/patterns/coordinated
# Last 30 minutes, tight grouping (200m)
curl "http://localhost:8090/api/patterns/coordinated?time_window_minutes=30&distance_threshold_m=200"
# Last 6 hours
curl "http://localhost:8090/api/patterns/coordinated?time_window_minutes=360"Detect operators flying multiple different drones (operator tracking, persistent surveillance).
Endpoint: GET /api/patterns/pilot-reuse
Use Case: Track operators across drone changes, identify professional operators
Parameters:
| Parameter | Type | Required | Default | Range | Description |
|---|---|---|---|---|---|
time_window_hours |
integer | No | 24 |
1-168 | Time window for analysis (hours) |
proximity_threshold_m |
integer | No | 50 |
≥10 | Pilot location proximity (meters) |
Response:
{
"pilot_reuse": [
{
"pilot_identifier": "OP12345678",
"correlation_method": "operator_id",
"drones": [
{
"drone_id": "DJI-DRONE1",
"timestamp": "2026-01-20T12:00:00Z",
"pilot_lat": 37.7750,
"pilot_lon": -122.4190
},
{
"drone_id": "DJI-DRONE2",
"timestamp": "2026-01-20T15:00:00Z",
"pilot_lat": 37.7751,
"pilot_lon": -122.4191
}
],
"drone_count": 2
}
],
"count": 1,
"time_window_hours": 24,
"proximity_threshold_m": 50
}Correlation Methods:
operator_id- Matched by Remote ID operator fieldproximity- Matched by pilot location clustering
Status Codes:
200 OK- Success422 Unprocessable Entity- Invalid parameters500 Internal Server Error- Database error503 Service Unavailable- Database unavailable
Example:
# Last 24 hours
curl http://localhost:8090/api/patterns/pilot-reuse
# Last 12 hours, 100m proximity
curl "http://localhost:8090/api/patterns/pilot-reuse?time_window_hours=12&proximity_threshold_m=100"Detect unusual or dangerous drone behavior (altitude, speed, or flight pattern anomalies).
Endpoint: GET /api/patterns/anomalies
Use Case: Identify dangerous drones, reckless pilots, or unusual behavior
Parameters:
| Parameter | Type | Required | Default | Range | Description |
|---|---|---|---|---|---|
time_window_hours |
integer | No | 1 |
1-24 | Time window for analysis (hours) |
Response:
{
"anomalies": [
{
"anomaly_type": "speed",
"severity": "high",
"drone_id": "DJI-FAST1234",
"details": {
"speed_mps": 45.5,
"threshold": 40.0,
"rid_make": "DJI",
"rid_model": "FPV Drone"
},
"timestamp": "2026-01-20T15:30:00Z"
},
{
"anomaly_type": "altitude",
"severity": "critical",
"drone_id": "DJI-HIGH5678",
"details": {
"altitude_m": 520.0,
"threshold": 500.0,
"rid_make": "DJI"
},
"timestamp": "2026-01-20T15:25:00Z"
},
{
"anomaly_type": "rapid_altitude_change",
"severity": "medium",
"drone_id": "DJI-CLIMB9999",
"details": {
"altitude_change_m": 85.0,
"time_window_s": 10,
"threshold": 75.0
},
"timestamp": "2026-01-20T15:20:00Z"
}
],
"count": 3,
"time_window_hours": 1
}Anomaly Types:
-
Speed Anomalies
critical: > 50 m/s (~180 km/h)high: > 40 m/s (~144 km/h)medium: > 30 m/s (~108 km/h)
-
Altitude Anomalies
critical: > 500m (above legal limit in most jurisdictions)high: > 450mmedium: > 400m (FAA limit)
-
Rapid Altitude Change
critical: > 100m in 10 secondshigh: > 75m in 10 secondsmedium: > 50m in 10 seconds
Status Codes:
200 OK- Success422 Unprocessable Entity- Invalid parameters500 Internal Server Error- Database error503 Service Unavailable- Database unavailable
Example:
# Last hour
curl http://localhost:8090/api/patterns/anomalies
# Last 6 hours
curl "http://localhost:8090/api/patterns/anomalies?time_window_hours=6"
# Last 24 hours
curl "http://localhost:8090/api/patterns/anomalies?time_window_hours=24"Find drones detected by multiple kits simultaneously (triangulation opportunities).
Endpoint: GET /api/patterns/multi-kit
Use Case: Identify triangulation opportunities, signal strength comparison, coverage analysis
Parameters:
| Parameter | Type | Required | Default | Range | Description |
|---|---|---|---|---|---|
time_window_minutes |
integer | No | 15 |
1-1440 | Time window for correlation (minutes) |
Response:
{
"multi_kit_detections": [
{
"drone_id": "DJI-TRIANGLE",
"kits": [
{
"kit_id": "kit-alpha",
"rssi": -65,
"lat": 37.7749,
"lon": -122.4194,
"timestamp": "2026-01-20T15:30:00Z"
},
{
"kit_id": "kit-bravo",
"rssi": -72,
"lat": 37.7760,
"lon": -122.4200,
"timestamp": "2026-01-20T15:30:05Z"
},
{
"kit_id": "kit-charlie",
"rssi": -68,
"lat": 37.7755,
"lon": -122.4185,
"timestamp": "2026-01-20T15:30:03Z"
}
],
"triangulation_possible": true
}
],
"count": 1,
"time_window_minutes": 15
}Triangulation Possible: true if detected by 3+ kits (enables geometric position estimation)
Use Cases:
- Triangulation - Calculate precise drone position from RSSI
- Signal Comparison - Analyze relative signal strengths
- Coverage Analysis - Understand kit detection overlap
- Quality Validation - Verify detection accuracy across kits
Status Codes:
200 OK- Success422 Unprocessable Entity- Invalid parameters500 Internal Server Error- Database error503 Service Unavailable- Database unavailable
Example:
# Last 15 minutes
curl http://localhost:8090/api/patterns/multi-kit
# Last 30 minutes
curl "http://localhost:8090/api/patterns/multi-kit?time_window_minutes=30"
# Last hour
curl "http://localhost:8090/api/patterns/multi-kit?time_window_minutes=60"Estimate drone location using RSSI-based triangulation from multiple kits, with GPS spoofing detection.
Endpoint: GET /api/analysis/estimate-location/{drone_id}
Use Cases:
- Test estimation algorithms against drones with known GPS positions
- Detect GPS spoofing by comparing reported position vs RSSI-estimated position
- Future: Estimate location for encrypted drones with only RSSI data
Path Parameters:
| Parameter | Type | Description |
|---|---|---|
drone_id |
string | The drone's unique identifier |
Query Parameters:
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
timestamp |
string | No | (now) | ISO 8601 timestamp for the observation |
time_window_seconds |
integer | No | 30 |
Time window around timestamp (5-300s) |
Response:
{
"drone_id": "DJI-TRIANGLE",
"timestamp": "2026-01-20T15:30:00Z",
"actual": {
"lat": 37.7749,
"lon": -122.4194
},
"estimated": {
"lat": 37.7752,
"lon": -122.4191
},
"error_meters": 42.3,
"confidence_radius_m": 150.5,
"observations": [
{
"kit_id": "kit-alpha",
"kit_lat": 37.7740,
"kit_lon": -122.4180,
"rssi": -65,
"time": "2026-01-20T15:30:00Z"
},
{
"kit_id": "kit-bravo",
"kit_lat": 37.7760,
"kit_lon": -122.4210,
"rssi": -72,
"time": "2026-01-20T15:30:02Z"
}
],
"algorithm": "two_kit_weighted",
"estimated_distances": [
{"kit_id": "kit-alpha", "distance_m": 178},
{"kit_id": "kit-bravo", "distance_m": 398}
],
"spoofing_score": 0.15,
"spoofing_suspected": false,
"spoofing_reason": null
}Response Fields:
actual- Drone's reported GPS position (null if no GPS data available)estimated- Calculated position based on RSSI trilaterationerror_meters- Distance between estimated and actual (null if no actual)confidence_radius_m- Estimated accuracy radiusobservations- Kit data used for calculationalgorithm- Algorithm used:single_kit,two_kit_weighted, ortrilaterationestimated_distances- Array of kit_id and estimated distance in meters (from RSSI)spoofing_score- 0.0-1.0 indicating likelihood of GPS spoofing (null if no actual position)spoofing_suspected- True if spoofing_score >= 0.5 (null if no actual position)spoofing_reason- Explanation when spoofing is suspected or warrants monitoring
Algorithm:
Uses the log-distance path loss model to convert RSSI to estimated distance:
distance = 10^((TxPower - RSSI) / (10 * n))
Then applies trilateration based on number of kits:
| Kits | Method | Description |
|---|---|---|
| 1 | single_kit |
Returns kit position with distance as confidence radius |
| 2 | two_kit_weighted |
Position along line between kits, weighted by inverse distance |
| 3+ | trilateration |
Iterative gradient descent to find best-fit position |
Spoofing Detection:
The endpoint compares the drone's reported GPS position against the RSSI-estimated position to detect potential GPS spoofing:
| Spoofing Score | Interpretation |
|---|---|
| 0.0 - 0.29 | Normal - position matches RSSI estimate |
| 0.30 - 0.49 | Warrants monitoring - some deviation |
| 0.50 - 0.69 | Suspicious - significant deviation |
| 0.70 - 1.0 | Likely spoofing - extreme deviation |
Status Codes:
200 OK- Success400 Bad Request- Invalid timestamp format or insufficient data404 Not Found- No observations found for drone in time window500 Internal Server Error- Calculation or database error
Examples:
# Estimate location at current time
curl "http://localhost:8090/api/analysis/estimate-location/DJI-TRIANGLE"
# Estimate location at specific timestamp
curl "http://localhost:8090/api/analysis/estimate-location/DJI-TRIANGLE?timestamp=2026-01-20T15:30:00Z"
# Estimate with wider time window
curl "http://localhost:8090/api/analysis/estimate-location/DJI-TRIANGLE?time_window_seconds=60"Spoofing Detection Example Response:
{
"drone_id": "SUSPICIOUS-DRONE",
"timestamp": "2026-01-20T15:30:00Z",
"actual": {
"lat": 37.7749,
"lon": -122.4194
},
"estimated": {
"lat": 37.7820,
"lon": -122.4300
},
"error_meters": 1250.8,
"confidence_radius_m": 180.0,
"observations": [...],
"algorithm": "trilateration",
"estimated_distances": [...],
"spoofing_score": 0.72,
"spoofing_suspected": true,
"spoofing_reason": "Position error (1251m) is 6.9x the expected accuracy (180m)"
}Estimate FPV signal source location using linear power weighting from multiple kits.
Endpoint: GET /api/analysis/estimate-signal-location
Use Cases:
- Triangulate FPV drone location when multiple kits detect the same frequency
- Locate signal sources without Remote ID (analog FPV)
- Correlate signal detections across distributed sensor network
Query Parameters:
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
freq_mhz |
float | Yes | - | Signal frequency in MHz (e.g., 5800.0) |
timestamp |
string | No | (now) | ISO 8601 timestamp for the observation |
time_window_seconds |
integer | No | 60 |
Time window around timestamp (5-300s) |
Response:
{
"freq_mhz": 5800.0,
"timestamp": "2026-01-20T15:30:00Z",
"estimated": {
"lat": 37.7752,
"lon": -122.4191
},
"confidence_radius_m": 250.5,
"observations": [
{
"kit_id": "kit-alpha",
"kit_lat": 37.7740,
"kit_lon": -122.4180,
"rssi": 0.752,
"freq_mhz": 5800.0,
"time": "2026-01-20T15:30:00Z",
"pal_conf": 85.0,
"ntsc_conf": 12.0
},
{
"kit_id": "kit-bravo",
"kit_lat": 37.7760,
"kit_lon": -122.4210,
"rssi": 0.483,
"freq_mhz": 5800.0,
"time": "2026-01-20T15:30:02Z",
"pal_conf": 78.0,
"ntsc_conf": 15.0
}
],
"algorithm": "linear_power_weighted",
"estimated_distances": null,
"kit_count": 2,
"triangulation_possible": false,
"warning": null
}Response Fields:
freq_mhz- The queried frequencyestimated- Calculated position based on signal power weightingconfidence_radius_m- Estimated accuracy radiusobservations- Kit data used for calculationrssi- Linear power (0-1 scale, higher = stronger signal, NOT dBm)pal_conf/ntsc_conf- Video standard confidence (0-100%)
algorithm- Algorithm used:single_kit_linear,linear_power_weighted, orlinear_power_multikitestimated_distances- Alwaysnullfor signals (distance cannot be calculated from linear power)kit_count- Number of kits that detected the signaltriangulation_possible- True if 3+ kits (improves accuracy)warning- Warning message if kits are geographically distant (>50km apart)
Algorithm:
Unlike drone triangulation which uses calibrated RSSI (dBm) to estimate distance, signal location uses linear power weighting. The FPV detector outputs raw signal power (0-1 scale) which cannot be converted to distance without SDR calibration.
| Kits | Method | Description |
|---|---|---|
| 1 | single_kit_linear |
Returns kit position with uncertainty radius based on signal strength |
| 2 | linear_power_weighted |
Weighted centroid where higher power = closer to that kit |
| 3+ | linear_power_multikit |
Weighted centroid with improved confidence from multiple observations |
Signal Power Values:
1.0= Very strong signal (source likely nearby)0.5= Medium signal strength0.1= Weak signal (source likely distant or obstructed)
Limitations:
- Linear power is relative, not calibrated - distance estimation is not possible
- If multiple transmitters share the same frequency, results will be mixed
- Kits geographically far apart (>50km) will produce unreliable results (warning returned)
- Accuracy improves with more kits and closer proximity
Status Codes:
200 OK- Success400 Bad Request- Invalid timestamp format or insufficient data404 Not Found- No signal observations found for frequency in time window500 Internal Server Error- Calculation or database error
Examples:
# Estimate location of 5800 MHz signal
curl "http://localhost:8090/api/analysis/estimate-signal-location?freq_mhz=5800.0"
# Estimate at specific timestamp
curl "http://localhost:8090/api/analysis/estimate-signal-location?freq_mhz=5800.0×tamp=2026-01-20T15:30:00Z"
# Estimate with shorter time window (30 seconds)
curl "http://localhost:8090/api/analysis/estimate-signal-location?freq_mhz=5800.0&time_window_seconds=30"Specialized endpoints for security monitoring and threat detection.
Get consolidated security alerts with threat scoring.
Endpoint: GET /api/patterns/security-alerts
Use Case: Prison perimeter monitoring, critical infrastructure protection, neighborhood surveillance
Parameters:
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
time_window_hours |
integer | No | 4 |
Time window (1-24 hours) |
Response:
{
"alerts": [
{
"time": "2026-01-20T15:30:00Z",
"drone_id": "DJI-SUSPECT1",
"threat_score": 85,
"threat_level": "high",
"indicators": ["rapid_descent", "night_activity", "loitering"]
}
],
"count": 5,
"time_window_hours": 4,
"threat_summary": {
"critical": 1,
"high": 2,
"medium": 1,
"low": 1
}
}Threat Levels:
critical- Immediate attention required (score ≥ 80)high- Significant concern (score 60-79)medium- Moderate concern (score 40-59)low- Minor concern (score < 40)
Detect drones hovering in a specific geographic area.
Endpoint: GET /api/patterns/loitering
Use Case: Monitor secure facilities, detect surveillance attempts
Parameters:
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
lat |
float | Yes | - | Center latitude of area |
lon |
float | Yes | - | Center longitude of area |
radius_m |
float | No | 500 |
Monitoring radius (50-5000m) |
min_duration_minutes |
integer | No | 5 |
Minimum time in area (1-120 min) |
time_window_hours |
integer | No | 24 |
Time window (1-168 hours) |
Response:
{
"loitering_drones": [
{
"drone_id": "DJI-LOITER1",
"duration_minutes": 12,
"entry_time": "2026-01-20T14:00:00Z",
"exit_time": "2026-01-20T14:12:00Z",
"avg_distance_m": 150.5
}
],
"count": 1,
"search_area": {
"center_lat": 37.7749,
"center_lon": -122.4194,
"radius_m": 500
},
"parameters": {
"min_duration_minutes": 5,
"time_window_hours": 24
}
}Example:
# Monitor 500m radius around coordinates
curl "http://localhost:8090/api/patterns/loitering?lat=37.7749&lon=-122.4194"
# Tighter radius, longer minimum loiter time
curl "http://localhost:8090/api/patterns/loitering?lat=37.7749&lon=-122.4194&radius_m=200&min_duration_minutes=10"Detect rapid altitude descents that may indicate payload drops.
Endpoint: GET /api/patterns/rapid-descent
Use Case: Contraband delivery detection, cargo drop monitoring
Parameters:
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
time_window_minutes |
integer | No | 60 |
Time window (5-1440 min) |
min_descent_rate_mps |
float | No | 5.0 |
Minimum descent rate (1-50 m/s) |
min_descent_m |
float | No | 30.0 |
Minimum total descent (10-500m) |
Response:
{
"descent_events": [
{
"drone_id": "DJI-DROP1",
"start_time": "2026-01-20T15:20:00Z",
"end_time": "2026-01-20T15:20:30Z",
"start_alt": 100.0,
"end_alt": 30.0,
"descent_m": 70.0,
"descent_rate_mps": 12.5,
"horizontal_speed_mps": 2.1,
"possible_payload_drop": true,
"lat": 37.7749,
"lon": -122.4194
}
],
"count": 1,
"possible_payload_drops": 1,
"parameters": {
"time_window_minutes": 60,
"min_descent_rate_mps": 5.0,
"min_descent_m": 30.0
}
}Note: Events with low horizontal speed during descent are flagged as possible_payload_drop: true.
Detect drone activity during night hours.
Endpoint: GET /api/patterns/night-activity
Use Case: Unauthorized night flights, contraband delivery detection
Parameters:
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
time_window_hours |
integer | No | 24 |
Time window (1-168 hours) |
night_start_hour |
integer | No | 22 |
Hour when night begins (0-23) |
night_end_hour |
integer | No | 5 |
Hour when night ends (0-23) |
Response:
{
"night_activity": [
{
"drone_id": "DJI-NIGHT1",
"first_seen": "2026-01-20T02:15:00Z",
"last_seen": "2026-01-20T02:45:00Z",
"detection_count": 12,
"risk_level": "high",
"avg_altitude": 50.0,
"kit_id": "kit-alpha"
}
],
"count": 1,
"risk_summary": {
"critical": 0,
"high": 1,
"medium": 0,
"low": 0
},
"parameters": {
"time_window_hours": 24,
"night_start_hour": 22,
"night_end_hour": 5
}
}Natural language query interface powered by Ollama LLM.
Note: These endpoints require Ollama to be installed and running. See ollama-setup.md for configuration.
Check if the LLM service is available.
Endpoint: GET /api/llm/status
Response:
{
"available": true,
"message": null,
"ollama_url": "http://localhost:11434",
"model": "llama3.1:8b",
"available_models": ["llama3.1:8b", "mistral:7b"]
}When unavailable:
{
"available": false,
"message": "Model llama3.1:8b not found. Available models: mistral:7b",
"ollama_url": "http://localhost:11434",
"model": "llama3.1:8b",
"available_models": ["mistral:7b"]
}Query drone data using natural language.
Endpoint: POST /api/llm/query
Request Body:
{
"question": "How many DJI drones were detected today?",
"session_id": "user-123",
"include_summary": true
}| Field | Type | Required | Description |
|---|---|---|---|
question |
string | Yes | Natural language question (3-1000 chars) |
session_id |
string | No | Session ID for conversation context |
include_summary |
boolean | No | Include natural language summary (default: true) |
Response:
{
"success": true,
"response": "Found 23 DJI drones detected today. The most common model was Mavic 3 (12 detections), followed by Mini 3 Pro (8 detections).",
"results": [
{
"rid_make": "DJI",
"rid_model": "Mavic 3",
"count": 12
},
{
"rid_make": "DJI",
"rid_model": "Mini 3 Pro",
"count": 8
}
],
"row_count": 2,
"query_executed": "SELECT rid_make, rid_model, COUNT(*) FROM drones WHERE rid_make = 'DJI' AND time >= NOW() - INTERVAL '24 hours' GROUP BY rid_make, rid_model",
"session_id": "user-123",
"error": null
}Example Questions:
- "What drones were seen in the last hour?"
- "Show me high altitude flights above 400 meters"
- "Any FPV signals detected today?"
- "Which manufacturer is most common?"
- "Drones with pilot location near 37.77, -122.41"
Get example queries for the UI.
Endpoint: GET /api/llm/examples
Response:
{
"examples": {
"Basic": [
"How many drones were detected today?",
"Show me DJI drones from the last hour"
],
"Filtering": [
"Drones flying above 100 meters",
"Any drones with pilot location?"
],
"Analysis": [
"Which manufacturer is most common?",
"Busiest time of day for detections"
]
}
}Clear conversation history for a session.
Endpoint: DELETE /api/llm/session/{session_id}
Path Parameters:
| Parameter | Type | Description |
|---|---|---|
session_id |
string | Session ID to clear |
Response:
{
"success": true,
"message": "Session user-123 cleared"
}All endpoints follow standard HTTP status codes.
| Code | Meaning | Common Causes |
|---|---|---|
200 OK |
Success | Request completed successfully |
422 Unprocessable Entity |
Invalid parameters | Parameter out of range, wrong type |
500 Internal Server Error |
Server error | Database query error, internal exception |
503 Service Unavailable |
Service unavailable | Database connection failed, pool unavailable |
Error Response Format:
{
"detail": "Error description here"
}{
time: string, // ISO 8601 timestamp
kit_id: string,
drone_id: string,
lat?: number, // WGS84 latitude
lon?: number, // WGS84 longitude
alt?: number, // Altitude in meters (AGL)
speed?: number, // Ground speed in m/s
heading?: number, // Heading in degrees (0-360)
pilot_lat?: number, // Pilot/operator latitude
pilot_lon?: number, // Pilot/operator longitude
home_lat?: number, // Home point latitude
home_lon?: number, // Home point longitude
mac?: string, // MAC address (if available)
rssi?: number, // Signal strength in dBm
freq?: number, // Frequency in MHz
ua_type?: string, // UA type (multirotor, fixed-wing, etc.)
operator_id?: string, // Remote ID operator identifier
caa_id?: string, // CAA registration ID
rid_make?: string, // Manufacturer (DJI, Autel, etc.)
rid_model?: string, // Model (Mavic 3, etc.)
rid_source?: string, // RID source (BLE, WiFi, etc.)
track_type?: string // "drone" or "aircraft"
}{
time: string, // ISO 8601 timestamp
kit_id: string,
freq_mhz: number, // Frequency in MHz
power_dbm?: number, // Linear signal power (0-1 scale, NOT dBm despite field name)
bandwidth_mhz?: number, // Bandwidth in MHz
lat?: number, // Detection location latitude
lon?: number, // Detection location longitude
alt?: number, // Detection altitude in meters
detection_type?: string // analog_fpv, dji_fpv, etc.
}{
kit_id: string,
name: string,
location?: string,
api_url: string,
last_seen?: string, // ISO 8601 timestamp
status: string, // online, stale, offline, unknown
created_at: string // ISO 8601 timestamp
}// Get drones from last hour
async function getDrones() {
const response = await fetch('http://localhost:8090/api/drones?time_range=1h');
const data = await response.json();
return data.drones;
}
// Get repeated drones
async function getRepeatedDrones(hours = 24) {
const response = await fetch(
`http://localhost:8090/api/patterns/repeated-drones?time_window_hours=${hours}`
);
const data = await response.json();
return data.repeated_drones;
}
// Display on map
async function updateMap() {
const drones = await getDrones();
drones.forEach(drone => {
if (drone.lat && drone.lon) {
addMarker(drone.lat, drone.lon, drone.drone_id);
}
});
}import requests
BASE_URL = "http://localhost:8090"
# Get all kits
def get_kits():
response = requests.get(f"{BASE_URL}/api/kits")
response.raise_for_status()
return response.json()["kits"]
# Get anomalies
def get_anomalies(hours=1):
params = {"time_window_hours": hours}
response = requests.get(f"{BASE_URL}/api/patterns/anomalies", params=params)
response.raise_for_status()
return response.json()["anomalies"]
# Export to CSV
def export_csv(filename="drones.csv", time_range="24h"):
params = {"time_range": time_range}
response = requests.get(f"{BASE_URL}/api/export/csv", params=params)
response.raise_for_status()
with open(filename, "wb") as f:
f.write(response.content)# Get health status
curl http://localhost:8090/health
# Get all kits
curl http://localhost:8090/api/kits
# Get drones from last 24 hours (pretty print with jq)
curl http://localhost:8090/api/drones?time_range=24h | jq
# Get coordinated activity
curl "http://localhost:8090/api/patterns/coordinated?time_window_minutes=30" | jq
# Export CSV
curl -o drones.csv "http://localhost:8090/api/export/csv?time_range=7d"
# Get all pattern metrics
curl -s http://localhost:8090/api/patterns/repeated-drones | jq '.count'
curl -s http://localhost:8090/api/patterns/coordinated | jq '.count'
curl -s http://localhost:8090/api/patterns/pilot-reuse | jq '.count'
curl -s http://localhost:8090/api/patterns/anomalies | jq '.count'
curl -s http://localhost:8090/api/patterns/multi-kit | jq '.count'{
"datasource": "WarDragon Analytics",
"url": "http://wardragon-api:8090/api/drones",
"params": {
"time_range": "1h",
"limit": 1000
},
"jsonPath": "$.drones[*]"
}| Endpoint | Time Window | Target Response Time |
|---|---|---|
/health |
N/A | < 50ms |
/api/kits |
N/A | < 100ms |
/api/drones |
1 hour | < 200ms |
/api/drones |
24 hours | < 500ms |
/api/signals |
1 hour | < 200ms |
/api/patterns/repeated-drones |
24 hours | < 300ms |
/api/patterns/coordinated |
1 hour | < 400ms |
/api/patterns/pilot-reuse |
24 hours | < 450ms |
/api/patterns/anomalies |
1 hour | < 200ms |
/api/patterns/multi-kit |
15 minutes | < 250ms |
- Use smaller time windows for real-time queries
- Limit results to what you actually need
- Filter early - use kit_id, rid_make, etc. to reduce data
- Cache results when appropriate
- Use multi-kit endpoint for triangulation (pre-aggregated)
All endpoints are optimized with TimescaleDB indexes on:
time(hypertable partitioning)kit_iddrone_idrid_maketrack_type- Pattern-specific indexes (pilot coordinates, RSSI, etc.)
Note: Optional authentication is available but disabled by default.
For production deployments:
- Enable authentication - Set
AUTH_ENABLED=truein.env(JWT-based, rate limited) - Configure alerting - Set
ALERTING_ENABLED=truefor Slack/Discord webhooks - Enable audit logging - Tracks admin actions, optionally stored in database
- Use HTTPS - Always encrypt API traffic in production
- Network isolation - Restrict API access to trusted networks
- Automated backups - Run
./scripts/setup-backup-cron.shfor daily backups
See SECURITY.md for complete security hardening guide.
- Phase 1: Core endpoints (health, kits, drones, signals, CSV export)
- Phase 2: Pattern detection endpoints (5 new endpoints)
- Database views and functions for pattern analysis
- Comprehensive error handling and validation
- Documentation: README.md, operator-guide.md
- Architecture: architecture.md
- Testing: testing.md
- Deployment: deployment.md
- Troubleshooting: troubleshooting.md
Last Updated: 2026-01-30 API Version: 1.0.0 WarDragon Analytics - Multi-kit drone surveillance platform