REST API Reference

SkySpy REST API Reference

Enterprise-Ready API for Real-Time Aircraft Tracking and Aviation Intelligence

Welcome to the SkySpy API documentation. This comprehensive guide covers authentication, endpoints, request/response formats, and error handling for integrating with SkySpy's powerful aircraft tracking platform.


Quick Start

sequenceDiagram
    participant Client
    participant API as SkySpy API
    participant DB as Database

    Client->>API: POST /auth/login
    API-->>Client: JWT tokens
    Client->>API: GET /aircraft/ (with Bearer token)
    API->>DB: Query tracked aircraft
    DB-->>API: Aircraft data
    API-->>Client: JSON response

API Overview

Base URL

EnvironmentURL
Productionhttps://your-domain.com/api/v1/
Developmenthttp://localhost:8000/api/v1/

API Version: v1 - All endpoints are prefixed with /api/v1/

Content Type

All requests and responses use JSON format:

Content-Type: application/json
Accept: application/json

Interactive Documentation

ToolURLDescription
Swagger UI/api/v1/docs/Interactive API explorer
ReDoc/api/v1/redoc/Beautiful API reference
OpenAPI Schema/api/v1/schema/Raw OpenAPI 3.0 spec

Tip: Visit /api/v1/docs/ for an interactive playground where you can test endpoints directly.


Authentication

SkySpy supports multiple authentication methods to accommodate different use cases.

Authentication Modes

ModeBadgeDescription
publicPublicAll endpoints accessible without authentication
authenticatedAuth RequiredAll endpoints require valid authentication
hybridHybridPublic read access, authentication required for writes

Check /api/v1/auth/config to discover the current authentication mode.

JWT Bearer Token (Primary)

The primary authentication method using JSON Web Tokens.

Request Header:

Authorization: Bearer <access_token>

Obtaining Tokens:

curl -X POST https://your-domain.com/api/v1/auth/login \
  -H "Content-Type: application/json" \
  -d '{
    "username": "your-username",
    "password": "your-password"
  }'
const response = await fetch('/api/v1/auth/login', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    username: 'your-username',
    password: 'your-password'
  })
});
const { access, refresh } = await response.json();
import requests

response = requests.post(
    'https://your-domain.com/api/v1/auth/login',
    json={
        'username': 'your-username',
        'password': 'your-password'
    }
)
tokens = response.json()

Response:

{
  "access": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9...",
  "refresh": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9...",
  "user": {
    "id": 1,
    "username": "your-username",
    "email": "[email protected]",
    "is_superuser": false,
    "roles": ["viewer"],
    "permissions": ["aircraft.view", "alerts.view"]
  }
}

Token Refresh:

curl -X POST https://your-domain.com/api/v1/auth/refresh \
  -H "Content-Type: application/json" \
  -d '{"refresh": "<refresh_token>"}'
API Key Authentication

For server-to-server integrations and automated systems.

Request Headers (choose one):

Authorization: ApiKey sk_live_xxxxxxxxxxxx

or

X-API-Key: sk_live_xxxxxxxxxxxx

API keys are scoped with specific permissions and can be managed through the user profile or admin interface.

Cookie-Based Authentication

JWT tokens can also be stored in HTTP-only cookies for browser-based applications:

CookiePurposeLifetime
access_tokenShort-lived access token~15 minutes
refresh_tokenLong-lived refresh token~7 days
OIDC (OpenID Connect)

Enterprise single sign-on support via OIDC providers.

sequenceDiagram
    participant User
    participant SkySpy
    participant OIDC as OIDC Provider

    User->>SkySpy: GET /auth/oidc/authorize
    SkySpy-->>User: Redirect to OIDC Provider
    User->>OIDC: Authenticate
    OIDC-->>User: Authorization code
    User->>SkySpy: GET /auth/oidc/callback?code=xxx
    SkySpy->>OIDC: Exchange code for tokens
    OIDC-->>SkySpy: ID token + access token
    SkySpy-->>User: SkySpy JWT tokens

Initiate OIDC Flow:

GET /api/v1/auth/oidc/authorize?redirect_uri=https://your-app.com/callback

Handle Callback:

GET /api/v1/auth/oidc/callback?code=<authorization_code>&state=<state>

Error Handling

Standard Error Format

{
  "error": "error_type",
  "detail": "Human-readable error description"
}

HTTP Status Codes

StatusDescription
200Success
201Created
204No Content (successful deletion)
400Bad Request - Invalid parameters
401Unauthorized - Authentication required
403Forbidden - Insufficient permissions
404Not Found
429Too Many Requests - Rate limit exceeded
500Internal Server Error
Error Examples

Authentication Error (401):

{
  "detail": "Authentication credentials were not provided."
}

Permission Error (403):

{
  "detail": "You do not have permission to perform this action."
}

Validation Error (400):

{
  "error": "validation_error",
  "detail": "lat and lon parameters are required"
}

Rate Limit Error (429):

{
  "detail": "Request was throttled. Expected available in 60 seconds."
}

Rate Limiting

API requests are subject to rate limiting to ensure fair usage.

Default Limits

Endpoint TypeLimitBadge
Authentication endpoints5 req/minRate Limited
General API endpoints100 req/minRate Limited
Heavy endpoints (export, bulk)10 req/minRate Limited

Rate Limit Headers

X-RateLimit-Limit: 100
X-RateLimit-Remaining: 95
X-RateLimit-Reset: 1640000000

Pagination

List endpoints support cursor-based or offset pagination.

Query Parameters

ParameterTypeDefaultDescription
limitinteger100Maximum items per page
offsetinteger0Number of items to skip

Paginated Response Format

{
  "count": 1250,
  "next": "/api/v1/alerts/history?limit=100&offset=100",
  "previous": null,
  "results": [...]
}

Endpoints


Authentication


GET /auth/config

Get Auth Configuration

Public Rate

Returns the current authentication configuration for the API.

curl https://your-domain.com/api/v1/auth/config

Response Fields:

FieldTypeDescription
auth_modestringCurrent auth mode (public, authenticated, hybrid)
local_login_enabledbooleanWhether username/password login is enabled
oidc_enabledbooleanWhether OIDC SSO is available
api_key_enabledbooleanWhether API key auth is available

Response:

{
  "auth_mode": "hybrid",
  "local_login_enabled": true,
  "oidc_enabled": true,
  "oidc_provider_name": "Authentik",
  "api_key_enabled": true,
  "allow_registration": false
}

POST /auth/login

Authenticate User

Public Rate

Authenticate with username and password to obtain JWT tokens.

Request Body:

FieldTypeRequiredDescription
usernamestringYesUser's username
passwordstringYesUser's password
curl -X POST https://your-domain.com/api/v1/auth/login \
  -H "Content-Type: application/json" \
  -d '{
    "username": "admin",
    "password": "your-password"
  }'
const response = await fetch('/api/v1/auth/login', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    username: 'admin',
    password: 'your-password'
  })
});

Response:

{
  "access": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9...",
  "refresh": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9...",
  "user": {
    "id": 1,
    "username": "admin",
    "email": "[email protected]",
    "is_superuser": true,
    "roles": ["admin"],
    "permissions": ["*"]
  }
}

POST /auth/logout

Invalidate Session

Auth Required Rate

Invalidate the current session and blacklist the refresh token.

curl -X POST https://your-domain.com/api/v1/auth/logout \
  -H "Authorization: Bearer $ACCESS_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"refresh": "<refresh_token>"}'

Response:

{
  "success": true,
  "message": "Successfully logged out"
}

POST /auth/refresh

Refresh Access Token

Public Rate

Obtain a new access token using a refresh token.

Request Body:

FieldTypeRequiredDescription
refreshstringYesValid refresh token

Response:

{
  "access": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9..."
}

GET /auth/profile

Get User Profile

Auth Required

Retrieve the authenticated user's profile including roles and permissions.

curl https://your-domain.com/api/v1/auth/profile \
  -H "Authorization: Bearer $ACCESS_TOKEN"

Response:

{
  "id": 1,
  "username": "user",
  "email": "[email protected]",
  "first_name": "John",
  "last_name": "Doe",
  "is_superuser": false,
  "roles": [
    {
      "id": 1,
      "name": "viewer",
      "permissions": ["aircraft.view", "alerts.view"]
    }
  ],
  "permissions": ["aircraft.view", "alerts.view", "history.view"],
  "api_keys": [
    {
      "id": 1,
      "name": "My API Key",
      "key_prefix": "sk_live_abc",
      "scopes": ["aircraft:read", "alerts:read"],
      "last_used": "2024-01-15T10:30:00Z",
      "created_at": "2024-01-01T00:00:00Z"
    }
  ]
}

PATCH /auth/profile

Update User Profile

Auth Required

Update the authenticated user's profile.

Request Body:

FieldTypeRequiredDescription
first_namestringNoUser's first name
last_namestringNoUser's last name
emailstringNoUser's email address

POST /auth/password

Change Password

Auth Required

Change the authenticated user's password.

Request Body:

FieldTypeRequiredDescription
current_passwordstringYesCurrent password
new_passwordstringYesNew password

Aircraft Tracking


GET /aircraft/

List All Aircraft

Public/Hybrid Rate

Get all currently tracked aircraft with optional filtering.

Query Parameters:

ParameterTypeDefaultDescription
militaryboolean-Filter military aircraft only
min_altinteger-Minimum altitude in feet
max_altinteger-Maximum altitude in feet
min_distancefloat-Minimum distance in NM
max_distancefloat-Maximum distance in NM
# Get all aircraft
curl https://your-domain.com/api/v1/aircraft/

# Get military aircraft under 10,000 ft
curl "https://your-domain.com/api/v1/aircraft/?military=true&max_alt=10000"
const aircraft = await fetch('/api/v1/aircraft/?military=true')
  .then(r => r.json());

console.log(`Tracking ${aircraft.count} military aircraft`);

Response:

{
  "aircraft": [
    {
      "hex": "A1B2C3",
      "flight": "UAL123",
      "type": "B738",
      "alt": 35000,
      "gs": 450,
      "vr": 0,
      "lat": 47.6062,
      "lon": -122.3321,
      "track": 180,
      "squawk": "1200",
      "category": "A3",
      "rssi": -28.5,
      "distance_nm": 15.2,
      "military": false,
      "emergency": false
    }
  ],
  "count": 42,
  "now": 1704067200.0,
  "messages": 1250000,
  "timestamp": "2024-01-01T00:00:00Z"
}

GET /aircraft/{icao_hex}/

Get Aircraft Detail

Public/Hybrid

Get detailed information for a specific aircraft including airframe data, photos, and matched radio calls.

Path Parameters:

ParameterTypeDescription
icao_hexstringICAO 24-bit hex identifier (e.g., A1B2C3)
curl https://your-domain.com/api/v1/aircraft/A1B2C3/

Response:

{
  "icao_hex": "A1B2C3",
  "registration": "N12345",
  "type_code": "B738",
  "type_name": "Boeing 737-800",
  "manufacturer": "Boeing",
  "model": "737-8AS",
  "serial_number": "12345",
  "year_built": 2015,
  "age_years": 9,
  "operator": "United Airlines",
  "operator_icao": "UAL",
  "owner": "United Airlines, Inc.",
  "country": "United States",
  "country_code": "US",
  "category": "A3",
  "is_military": false,
  "photo_url": "/api/v1/photos/A1B2C3",
  "photo_thumbnail_url": "/api/v1/photos/A1B2C3/thumb",
  "photo_photographer": "John Doe",
  "photo_source": "JetPhotos",
  "source_data": [...],
  "matched_radio_calls": [...]
}

GET /aircraft/top/

Get Top Aircraft

Public/Hybrid

Get notable aircraft sorted by various criteria (closest, highest, fastest, etc.).

Query Parameters:

ParameterTypeDefaultDescription
limitinteger5Number of aircraft per category

Response:

{
  "closest": [...],
  "highest": [...],
  "fastest": [...],
  "climbing": [...],
  "military": [...],
  "total": 42,
  "timestamp": "2024-01-01T00:00:00Z"
}

GET /aircraft/stats/

Get Aircraft Statistics

Public/Hybrid

Get statistical summary of currently tracked aircraft.

Response:

{
  "total": 42,
  "with_position": 38,
  "military": 3,
  "emergency": [],
  "categories": {
    "A1": 5,
    "A3": 25,
    "A5": 8
  },
  "altitude": {
    "0-10000": 10,
    "10000-25000": 15,
    "25000-40000": 12,
    "40000+": 5
  },
  "messages": 1250000,
  "timestamp": "2024-01-01T00:00:00Z"
}

GET /aircraft/geojson/

Get Aircraft GeoJSON

Public/Hybrid

Get aircraft positions in GeoJSON format for mapping applications.

Response:

{
  "type": "FeatureCollection",
  "features": [
    {
      "type": "Feature",
      "id": "A1B2C3",
      "geometry": {
        "type": "Point",
        "coordinates": [-122.3321, 47.6062]
      },
      "properties": {
        "hex": "A1B2C3",
        "flight": "UAL123",
        "altitude": 35000,
        "track": 180
      }
    }
  ],
  "metadata": {
    "count": 42,
    "timestamp": "2024-01-01T00:00:00Z"
  }
}

POST /aircraft/bulk-info/

Bulk Aircraft Info

Public/Hybrid Rate

Get information for multiple aircraft at once.

Request Body:

FieldTypeRequiredDescription
icao_listarrayYesArray of ICAO hex codes
curl -X POST https://your-domain.com/api/v1/aircraft/bulk-info/ \
  -H "Content-Type: application/json" \
  -d '{"icao_list": ["A1B2C3", "D4E5F6", "G7H8I9"]}'

Response:

{
  "aircraft": {
    "A1B2C3": {
      "registration": "N12345",
      "type_code": "B738",
      "operator": "United Airlines"
    },
    "D4E5F6": {
      "registration": "N67890",
      "type_code": "A320",
      "operator": "Delta Air Lines"
    }
  },
  "found": 2,
  "requested": 3
}

Aircraft Photos


GET /photos/{icao_hex}

Get Aircraft Photo

Public

Retrieve a cached aircraft photo. Returns the image file directly with appropriate Content-Type header.


GET /photos/{icao_hex}/thumb

Get Aircraft Thumbnail

Public

Retrieve a cached aircraft photo thumbnail.


Alert Rules


GET /alerts/rules/

List Alert Rules

Auth Optional

Get all alert rules accessible to the current user.

Query Parameters:

ParameterTypeDescription
enabledbooleanFilter by enabled status
prioritystringFilter by priority (info, warning, critical)
visibilitystringFilter by visibility (private, shared, public)

Response:

{
  "rules": [
    {
      "id": 1,
      "name": "Military Aircraft",
      "type": "military",
      "operator": "eq",
      "value": "true",
      "conditions": null,
      "description": "Alert when military aircraft detected",
      "enabled": true,
      "priority": "info",
      "cooldown_minutes": 5,
      "last_triggered": "2024-01-01T00:00:00Z",
      "visibility": "private",
      "notification_channels": [...],
      "is_owner": true,
      "can_edit": true,
      "can_delete": true
    }
  ],
  "count": 1
}

POST /alerts/rules/

Create Alert Rule

Auth Required Permission

Create a new alert rule.

flowchart LR
    A[Create Rule] --> B{Type}
    B -->|Simple| C[type + operator + value]
    B -->|Complex| D[conditions with AND/OR logic]
    C --> E[Evaluate against aircraft]
    D --> E
    E -->|Match| F[Trigger Alert]
    F --> G[Send Notifications]

Simple Rule Request:

FieldTypeRequiredDescription
namestringYesRule name
typestringYesRule type (military, squawk, callsign, etc.)
operatorstringYesComparison operator (eq, ne, lt, gt, in, contains)
valuestringYesValue to compare against
prioritystringNoPriority level (info, warning, critical)
enabledbooleanNoWhether rule is active
cooldown_minutesintegerNoMinutes between repeat alerts

Simple Rule Example - Alert on emergency squawks:

curl -X POST https://your-domain.com/api/v1/alerts/rules/ \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Emergency Squawk",
    "type": "squawk",
    "operator": "in",
    "value": "7500,7600,7700",
    "priority": "critical",
    "cooldown_minutes": 0
  }'

Complex Rule Example - Low-flying military aircraft:

curl -X POST https://your-domain.com/api/v1/alerts/rules/ \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Low Military Aircraft",
    "conditions": {
      "logic": "AND",
      "groups": [
        {
          "logic": "AND",
          "conditions": [
            {"type": "military", "operator": "eq", "value": "true"},
            {"type": "altitude", "operator": "lt", "value": "5000"}
          ]
        }
      ]
    },
    "priority": "warning"
  }'

PATCH /alerts/rules/{id}/

Update Alert Rule

Auth Required Permission

Update an existing alert rule.


DELETE /alerts/rules/{id}/

Delete Alert Rule

Auth Required Permission

Delete an alert rule. Returns 204 No Content on success.


POST /alerts/rules/test/

Test Alert Rule

Auth Required

Test a rule configuration against current or provided aircraft data.

curl -X POST https://your-domain.com/api/v1/alerts/rules/test/ \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "rule": {
      "type": "altitude",
      "operator": "lt",
      "value": "1000"
    },
    "aircraft": [
      {"hex": "A1B2C3", "alt_baro": 500},
      {"hex": "D4E5F6", "alt_baro": 5000}
    ]
  }'

Response:

{
  "matches": [
    {"hex": "A1B2C3", "alt_baro": 500}
  ],
  "match_count": 1,
  "tested_count": 2
}

POST /alerts/rules/bulk-toggle/

Bulk Toggle Rules

Auth Required

Enable or disable multiple rules at once.


GET /alerts/rules/export/

Export Rules

Auth Required

Export alert rules as JSON for backup or sharing.


POST /alerts/rules/import/

Import Rules

Auth Required

Import alert rules from JSON.


Alert History


GET /alerts/history/

List Alert History

Auth Optional

Get triggered alert history.

Query Parameters:

ParameterTypeDefaultDescription
rule_idinteger-Filter by rule ID
prioritystring-Filter by priority
acknowledgedboolean-Filter by acknowledgment status
hoursinteger24Time range in hours
limitinteger100Maximum results
offsetinteger0Pagination offset

Response:

{
  "history": [
    {
      "id": 1,
      "rule_id": 1,
      "rule_name": "Military Aircraft",
      "icao": "AE1234",
      "callsign": "EVAC01",
      "message": "Military aircraft detected: EVAC01",
      "priority": "info",
      "aircraft_data": {
        "hex": "AE1234",
        "flight": "EVAC01",
        "alt": 15000,
        "type": "C130"
      },
      "timestamp": "2024-01-01T12:00:00Z",
      "acknowledged": false
    }
  ],
  "count": 1
}

POST /alerts/history/{id}/acknowledge/

Acknowledge Alert

Auth Required

Mark an alert as acknowledged.


POST /alerts/history/bulk-acknowledge/

Bulk Acknowledge Alerts

Auth Required

Acknowledge multiple alerts at once.


Notification Channels


GET /notifications/channels/

List Notification Channels

Auth Required

Get configured notification channels.

Response:

{
  "channels": [
    {
      "id": 1,
      "name": "Discord Alerts",
      "channel_type": "discord",
      "config": {
        "webhook_url": "https://discord.com/api/webhooks/..."
      },
      "enabled": true,
      "verified": true,
      "last_used": "2024-01-01T12:00:00Z"
    }
  ],
  "count": 1
}

POST /notifications/channels/

Create Notification Channel

Auth Required

Create a new notification channel.

Discord webhook:

curl -X POST https://your-domain.com/api/v1/notifications/channels/ \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Discord Alerts",
    "channel_type": "discord",
    "config": {
      "webhook_url": "https://discord.com/api/webhooks/..."
    }
  }'

Email channel:

curl -X POST https://your-domain.com/api/v1/notifications/channels/ \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Email Alerts",
    "channel_type": "email",
    "config": {
      "recipients": ["[email protected]"]
    }
  }'

Custom webhook:

curl -X POST https://your-domain.com/api/v1/notifications/channels/ \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Custom Webhook",
    "channel_type": "webhook",
    "config": {
      "url": "https://your-server.com/webhook",
      "method": "POST",
      "headers": {"Authorization": "Bearer your-token"}
    }
  }'

POST /notifications/channels/{id}/test/

Test Notification Channel

Auth Required

Send a test notification to verify configuration.


Safety Events


GET /safety/events/

List Safety Events

Public/Hybrid

Get safety monitoring events (TCAS alerts, conflicts, etc.).

Query Parameters:

ParameterTypeDefaultDescription
event_typestring-Filter by type (tcas_ra, tcas_ta, conflict, separation)
severitystring-Filter by severity (info, warning, critical)
hoursinteger24Time range in hours
icaostring-Filter by aircraft ICAO hex
acknowledgedboolean-Filter by acknowledgment status

Response:

{
  "events": [
    {
      "id": 1,
      "event_type": "tcas_ra",
      "severity": "critical",
      "icao": "A1B2C3",
      "icao_2": "D4E5F6",
      "callsign": "UAL123",
      "callsign_2": "DAL456",
      "message": "TCAS Resolution Advisory between UAL123 and DAL456",
      "details": {
        "vertical_separation_ft": 400,
        "horizontal_separation_nm": 0.5
      },
      "timestamp": "2024-01-01T12:00:00Z"
    }
  ],
  "count": 1
}

GET /safety/events/{id}/

Get Safety Event Detail

Public/Hybrid

Get detailed information about a specific safety event.


POST /safety/events/{id}/acknowledge/

Acknowledge Safety Event

Auth Required

Mark a safety event as reviewed.


GET /safety/stats/

Get Safety Statistics

Public/Hybrid

Get safety monitoring statistics.

Response:

{
  "monitoring_enabled": true,
  "thresholds": {
    "vertical_separation_ft": 1000,
    "horizontal_separation_nm": 3.0
  },
  "time_range_hours": 24,
  "events_by_type": {
    "tcas_ra": 2,
    "tcas_ta": 15,
    "conflict": 5
  },
  "events_by_severity": {
    "critical": 2,
    "warning": 10,
    "info": 10
  },
  "total_events": 22,
  "event_rate_per_hour": 0.92
}

GET /safety/aircraft/{icao_hex}/stats/

Get Aircraft Safety Stats

Public/Hybrid

Get safety statistics for a specific aircraft.


History


GET /history/sightings/

List Sightings

Public/Hybrid

Get historical aircraft sighting records.

Query Parameters:

ParameterTypeDefaultDescription
icaostring-Filter by ICAO hex
callsignstring-Filter by callsign
startdatetime-Start timestamp (ISO 8601)
enddatetime-End timestamp (ISO 8601)
militaryboolean-Filter military only
limitinteger100Maximum results
offsetinteger0Pagination offset

GET /history/sessions/

List Sessions

Public/Hybrid

Get aircraft tracking sessions.

Query Parameters:

ParameterTypeDefaultDescription
icaostring-Filter by ICAO hex
hoursinteger24Time range in hours
militaryboolean-Filter military only
min_durationinteger-Minimum session duration in minutes
limitinteger100Maximum results

GET /history/stats/

Get History Statistics

Public/Hybrid

Get historical tracking statistics.


GET /history/trends/

Get Trends

Public/Hybrid

Get time-series trend data.

Query Parameters:

ParameterTypeDefaultDescription
hoursinteger24Time range in hours
intervalstringhourInterval type (15min, hour, day)

GET /history/top/

Get Top Performers

Public/Hybrid

Get notable tracking sessions (longest tracked, furthest distance, etc.).


Aviation Data


GET /aviation/metar/

Get METAR

Public

Get current METAR weather observations.

Query Parameters:

ParameterTypeDescription
icaostringAirport ICAO code (e.g., KSEA)
latfloatCenter latitude for area search
lonfloatCenter longitude for area search
radius_nmfloatSearch radius in nautical miles
# Get METAR for specific airport
curl "https://your-domain.com/api/v1/aviation/metar/?icao=KSEA"

# Get METARs within 50nm of a location
curl "https://your-domain.com/api/v1/aviation/metar/?lat=47.6&lon=-122.3&radius_nm=50"

Response:

{
  "data": [
    {
      "icao": "KSEA",
      "observation_time": "2024-01-01T12:00:00Z",
      "raw_text": "KSEA 011200Z 18008KT 10SM FEW040 12/08 A3012",
      "temp_c": 12,
      "dewpoint_c": 8,
      "wind_dir": 180,
      "wind_speed_kt": 8,
      "visibility_sm": 10,
      "altimeter_hg": 30.12,
      "flight_category": "VFR"
    }
  ],
  "count": 1,
  "source": "aviationweather.gov",
  "cached": true,
  "cache_age_seconds": 120
}

GET /aviation/taf/

Get TAF

Public

Get terminal aerodrome forecasts.


GET /aviation/pireps/

Get PIREPs

Public

Get pilot reports.

Query Parameters:

ParameterTypeDefaultDescription
latfloat-Center latitude
lonfloat-Center longitude
radius_nmfloat100Search radius
hoursinteger6Time range in hours

GET /aviation/airports/

Get Airports

Public

Get airport information.


GET /aviation/navaids/

Get Navaids

Public

Get navigation aids.


GET /aviation/airspace/

Get Airspace

Public

Get airspace boundaries and advisories.


NOTAMs


GET /notams/

List NOTAMs

Public

Get Notices to Air Missions.

Query Parameters:

ParameterTypeDefaultDescription
icaostring-Airport ICAO code
latfloat-Center latitude for area search
lonfloat-Center longitude for area search
radius_nmfloat100Search radius
typestring-NOTAM type filter (D, FDC, TFR, GPS)
active_onlybooleantrueOnly active NOTAMs
limitinteger100Maximum results

GET /notams/tfrs/

Get TFRs

Public

Get Temporary Flight Restrictions.


GET /notams/nearby/

Get Nearby NOTAMs

Public

Get NOTAMs near a specific location.

Query Parameters:

ParameterTypeRequiredDescription
latfloatYesCenter latitude
lonfloatYesCenter longitude
radius_nmfloatNoSearch radius (default: 50)

GET /notams/airport/{icao}/

Get Airport NOTAMs

Public

Get all NOTAMs for a specific airport.


GET /notams/stats/

Get NOTAM Statistics

Public

Get NOTAM cache statistics.


POST /notams/refresh/

Refresh NOTAMs

Auth Required Permission

Manually trigger a NOTAM cache refresh.


ACARS Messages


GET /acars/

List ACARS Messages

Public/Hybrid

Get ACARS/CPDLC messages.

Query Parameters:

ParameterTypeDefaultDescription
icaostring-Filter by aircraft ICAO hex
flightstring-Filter by flight number
labelstring-Filter by ACARS label
hoursinteger24Time range in hours
limitinteger100Maximum results

Response:

{
  "messages": [
    {
      "id": 1,
      "timestamp": "2024-01-01T12:00:00Z",
      "icao_hex": "A1B2C3",
      "registration": "N12345",
      "flight": "UAL123",
      "label": "H1",
      "text": "POSITION REPORT...",
      "decoded": {
        "type": "position",
        "lat": 47.6,
        "lon": -122.3
      },
      "source": "VDL2"
    }
  ],
  "count": 50
}

GET /acars/stats/

Get ACARS Statistics

Public/Hybrid

Get ACARS reception statistics.


Audio Transmissions


GET /audio/

List Audio Transmissions

Public/Hybrid

Get recorded radio transmissions.

Query Parameters:

ParameterTypeDefaultDescription
frequencyfloat-Filter by frequency in MHz
channelstring-Filter by channel name
hoursinteger24Time range in hours
transcribedboolean-Filter by transcription status
limitinteger100Maximum results

GET /audio/{id}/file

Get Audio File

Public/Hybrid

Download an audio transmission file. Returns audio file with appropriate Content-Type (audio/mpeg, audio/wav).


GET /audio/stats/

Get Audio Statistics

Public/Hybrid

Get audio reception statistics.


Map Data


GET /map/overlays/

Get Map Overlays

Public

Get GeoJSON overlays for map display.

Query Parameters:

ParameterTypeDescription
typestringOverlay type (artcc, fir, class_b, etc.)
bboxstringBounding box (min_lon,min_lat,max_lon,max_lat)

GET /map/routes/

Get Routes

Public

Get common flight routes.

Query Parameters:

ParameterTypeDescription
originstringOrigin airport ICAO
destinationstringDestination airport ICAO

Cannonball Mode

Law enforcement aircraft detection and tracking

sequenceDiagram
    participant User as Mobile User
    participant API as SkySpy API
    participant DB as Aircraft DB
    participant AI as Pattern Analysis

    User->>API: POST /cannonball/activate/
    API-->>User: Session started
    loop Every 5 seconds
        User->>API: POST /cannonball/location/
        API->>DB: Query nearby aircraft
        DB-->>API: Aircraft positions
        API->>AI: Analyze flight patterns
        AI-->>API: Pattern matches
        API-->>User: Threat assessment
    end
    User->>API: DELETE /cannonball/activate/
    API-->>User: Session ended

GET /cannonball/threats/

Get Threats

Auth Required

Get real-time threat data based on user location.

Query Parameters:

ParameterTypeRequiredDescription
latfloatYesUser latitude
lonfloatYesUser longitude
range_nmfloatNoDetection range (default: 15)

Response:

{
  "threats": [
    {
      "icao_hex": "A1B2C3",
      "callsign": "N1234P",
      "lat": 47.5,
      "lon": -122.4,
      "altitude": 1500,
      "ground_speed": 90,
      "distance_nm": 3.5,
      "bearing": 45,
      "closing_speed": 25,
      "threat_level": "warning",
      "urgency_score": 0.75,
      "is_known_le": true,
      "identification_method": "database",
      "identification_reason": "Known police helicopter",
      "operator_name": "Seattle Police",
      "patterns": [
        {
          "type": "circling",
          "confidence": 0.85,
          "duration_seconds": 300
        }
      ]
    }
  ],
  "timestamp": "2024-01-01T12:00:00Z"
}

POST /cannonball/location/

Update Location

Auth Required

Update user location for threat tracking.

Request Body:

FieldTypeRequiredDescription
latfloatYesCurrent latitude
lonfloatYesCurrent longitude
headingintegerNoCurrent heading (0-360)
speedfloatNoCurrent speed

POST /cannonball/activate/

Activate Cannonball Mode

Auth Required

Activate threat detection mode with custom settings.

curl -X POST https://your-domain.com/api/v1/cannonball/activate/ \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "lat": 47.6062,
    "lon": -122.3321,
    "settings": {
      "max_range_nm": 15,
      "alert_distance_nm": 5,
      "voice_enabled": true,
      "patterns_enabled": ["circling", "loitering", "grid_search"]
    }
  }'

DELETE /cannonball/activate/

Deactivate Cannonball Mode

Auth Required

Deactivate threat detection mode.


GET /cannonball/sessions/

List Sessions

Auth Required

Get Cannonball tracking sessions.


GET /cannonball/patterns/

List Patterns

Auth Required

Get detected flight patterns.


GET /cannonball/alerts/

List Cannonball Alerts

Auth Required

Get Cannonball-specific alerts.


GET /cannonball/known/

Get Known Aircraft Database

Auth Required

Get known law enforcement aircraft.


POST /cannonball/known/

Add Known Aircraft

Auth Required

Add an aircraft to the known LE database.


Mobile Position API

Mobile device position tracking for Cannonball mode


POST /mobile/position/

Update Position

Public

Update mobile device position and get nearby threats.

Request Body:

FieldTypeRequiredDescription
latfloatYesCurrent latitude
lonfloatYesCurrent longitude
session_idstringNoOptional session ID
headingintegerNoCurrent heading
radius_nmfloatNoSearch radius (default: 25)

GET /mobile/threats/

Get Threats

Public

Get threats for a stored session position.

Query Parameters:

ParameterTypeRequiredDescription
session_idstringYesSession ID from position update
radius_nmfloatNoThreat radius (default: 25)

POST /mobile/session/start/

Start Session

Public

Start a new mobile tracking session.


POST /mobile/session/end/

End Session

Public

End a mobile tracking session.


GET /mobile/session/history/

Get Session History

Public

Get encounter history for a persistent session.


System


GET /health

Health Check

Public

Basic health check endpoint (no authentication required).

curl https://your-domain.com/health

Response:

{
  "status": "healthy",
  "services": {
    "database": {"status": "up", "latency_ms": 2.5},
    "redis": {"status": "up", "latency_ms": 0.8},
    "celery": {"status": "up"}
  },
  "timestamp": "2024-01-01T12:00:00Z"
}

GET /system/status/

System Status

Public/Hybrid

Get comprehensive system status.

Response:

{
  "version": "2.0.0",
  "adsb_online": true,
  "aircraft_count": 42,
  "total_sightings": 125000,
  "total_sessions": 850,
  "active_rules": 15,
  "safety_monitoring_enabled": true,
  "redis_enabled": true,
  "websocket_connections": 5,
  "celery_running": true
}

GET /system/info/

API Info

Public

Get API information and available endpoints.


GET /metrics

Prometheus Metrics

Public

Get metrics in Prometheus format.

Response:

# HELP skyspy_aircraft_count Current number of tracked aircraft
# TYPE skyspy_aircraft_count gauge
skyspy_aircraft_count 42
# HELP skyspy_messages_total Total ADS-B messages received
# TYPE skyspy_messages_total counter
skyspy_messages_total 1250000

Archive


GET /archive/export/

Export Data

Auth Required Rate

Export historical data for archival.

Query Parameters:

ParameterTypeDescription
startdatetimeStart timestamp (ISO 8601)
enddatetimeEnd timestamp (ISO 8601)
formatstringExport format (json, csv)
typestringData type (sightings, sessions, alerts)

Statistics


GET /stats/

Get Current Statistics

Public/Hybrid

Get real-time feeder statistics.

Response:

{
  "aircraft_count": 42,
  "aircraft_with_position": 38,
  "military_count": 3,
  "messages_per_second": 450,
  "range_nm": {
    "current": 185,
    "max_today": 250,
    "max_ever": 285
  },
  "signal_strength": {
    "avg_rssi": -28.5,
    "best_rssi": -15.2
  },
  "uptime_seconds": 86400,
  "timestamp": "2024-01-01T00:00:00Z"
}

GET /stats/antenna/

Get Antenna Statistics

Public/Hybrid

Get antenna performance metrics.


Airframe Data


GET /airframe/{identifier}/

Lookup Airframe

Public

Look up aircraft information by ICAO hex or registration.

Path Parameters:

ParameterTypeDescription
identifierstringICAO hex (A1B2C3) or registration (N12345)

POST /airframe/{icao_hex}/refresh/

Refresh Airframe Data

Auth Required

Force refresh of airframe data from external sources.


Socket.IO API (real-time)

Real-time data is available via Socket.IO (path /socket.io, default namespace /). Use the same host as the REST API; authenticate by passing a token in the auth object when connecting.

  • Connection: io(origin, { path: '/socket.io', auth: { token: accessToken } })
  • Topics: Subscribe after connect with emit('subscribe', { topics: ['aircraft', 'safety', ...] }). Use topic all for every stream.
  • Events: Server emits aircraft:snapshot, aircraft:update, safety:event, alert:triggered, response, error, etc.

For full details, event shapes, request types, and namespaces (/, /audio, /cannonball), see the Socket.IO API Reference.


SDK and Code Examples

Python
import requests

BASE_URL = "https://your-domain.com/api/v1"

# Login
response = requests.post(f"{BASE_URL}/auth/login", json={
    "username": "user",
    "password": "password"
})
tokens = response.json()
access_token = tokens["access"]

# Get aircraft
headers = {"Authorization": f"Bearer {access_token}"}
aircraft = requests.get(f"{BASE_URL}/aircraft/", headers=headers).json()

print(f"Tracking {aircraft['count']} aircraft")

# Create an alert rule
rule = requests.post(f"{BASE_URL}/alerts/rules/",
    headers=headers,
    json={
        "name": "Military Aircraft",
        "type": "military",
        "operator": "eq",
        "value": "true",
        "priority": "info"
    }
).json()

print(f"Created rule: {rule['name']}")
JavaScript
const BASE_URL = 'https://your-domain.com/api/v1';

// Login
const loginResponse = await fetch(`${BASE_URL}/auth/login`, {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({ username: 'user', password: 'password' })
});
const { access } = await loginResponse.json();

// Get aircraft
const aircraftResponse = await fetch(`${BASE_URL}/aircraft/`, {
  headers: { 'Authorization': `Bearer ${access}` }
});
const aircraft = await aircraftResponse.json();

console.log(`Tracking ${aircraft.count} aircraft`);

// Socket.IO connection
import { io } from 'socket.io-client';

const socket = io('https://your-domain.com', {
  auth: { token: access },
  transports: ['websocket']
});

socket.on('connect', () => {
  socket.emit('subscribe', { topics: ['aircraft'] });
});

socket.on('aircraft:update', (data) => {
  console.log('Aircraft update:', data);
});
cURL
# Set your domain
API_URL="https://your-domain.com/api/v1"

# Login and extract token
TOKEN=$(curl -s -X POST "$API_URL/auth/login" \
  -H "Content-Type: application/json" \
  -d '{"username":"user","password":"password"}' | jq -r '.access')

# Get all aircraft
curl -s "$API_URL/aircraft/" \
  -H "Authorization: Bearer $TOKEN" | jq '.count'

# Get military aircraft only
curl -s "$API_URL/aircraft/?military=true" \
  -H "Authorization: Bearer $TOKEN" | jq '.aircraft[] | {hex, flight, type}'

# Create an alert rule
curl -s -X POST "$API_URL/alerts/rules/" \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Emergency Squawk",
    "type": "squawk",
    "operator": "in",
    "value": "7500,7600,7700",
    "priority": "critical"
  }' | jq '.id'

# Get METAR weather
curl -s "$API_URL/aviation/metar/?icao=KSEA" | jq '.data[0].raw_text'

Changelog

Version 2.0.0

  • Added Cannonball Mode endpoints for law enforcement aircraft detection
  • Added Mobile Position API for real-time threat tracking
  • Added notification channel management
  • Added complex alert conditions with nested logic
  • Added safety event monitoring and statistics
  • Added OIDC authentication support
  • Added API key authentication with scopes
  • Added feature-based permissions system

Version 1.0.0

  • Initial release with core aircraft tracking
  • Alert rules and history
  • Historical sightings and sessions
  • Aviation data (METAR, TAF, PIREPs)
  • ACARS message handling
  • Audio transmission recording

Need help? Check out our Getting Started Guide or visit the interactive API explorer.