Menu
Back to Documentation Index

API Documentation

Complete API guide with examples and integration patterns

VATSWIM API Documentation

Version: 1.2.0 Last Updated: March 25, 2026 Status: Production Ready API Base URL: https://perti.vatcscc.org/api/swim/v1 WebSocket URL: wss://perti.vatcscc.org/api/swim/v1/ws


FIXM Field Naming

The VATSWIM API supports both legacy and FIXM-aligned field names. The default response format uses legacy names for backward compatibility. Use ?format=fixm to receive FIXM-aligned names.

Legacy Name (Default) FIXM-Aligned Name (?format=fixm)
out_utc actual_off_block_time
off_utc actual_time_of_departure
on_utc actual_landing_time
in_utc actual_in_block_time
eta_utc estimated_time_of_arrival
etd_utc estimated_off_block_time

Implementation details:

  • SWIM database stores both legacy and FIXM column names (dual-write)
  • Default API responses use legacy field names
  • ?format=fixm returns FIXM-aligned field names
  • ADL database retains legacy column names (source of truth)
  • Ingest endpoints accept both legacy and FIXM input names

See VATSWIM_FIXM_Field_Mapping.md for complete mapping.


Table of Contents

  1. Overview
  2. Authentication
  3. REST API Endpoints
  4. WebSocket Real-Time API
  5. Data Models
  6. Python SDK
  7. Configuration Reference
  8. Database Schema
  9. Deployment & Operations
  10. Implementation Status

1. Overview

1.1 What is VATSWIM?

VATSWIM (System Wide Information Management) is a comprehensive API that provides access to real-time and historical flight data from the VATSIM virtual air traffic control network. The API follows FAA SWIM and FIXM (Flight Information Exchange Model) standards to provide standardized flight data to external consumers.

1.2 Key Features

  • REST API for querying flight data, positions, and traffic management initiatives (TMIs)
  • WebSocket API for real-time event streaming (departures, arrivals, position updates)
  • FIXM-aligned field naming with optional legacy format support
  • GeoJSON output for position data
  • Tiered access control with API key authentication
  • Python SDK for easy client integration

1.3 Architecture Overview

┌─────────────────┐      ┌─────────────────┐      ┌─────────────────┐
│  VATSIM Network │─────▶│   ADL Daemon    │─────▶│   SWIM_API DB   │
│   (live data)   │      │  (15s refresh)  │      │  (Azure SQL)    │
└─────────────────┘      └────────┬────────┘      └────────┬────────┘
                                  │                        │
                                  │ events                 │ queries
                                  ▼                        ▼
                         ┌─────────────────┐      ┌─────────────────┐
                         │   WebSocket     │      │    REST API     │
                         │    Server       │      │   Endpoints     │
                         └────────┬────────┘      └────────┬────────┘
                                  │                        │
                    ┌─────────────┴────────────────────────┴─────────────┐
                    │                  SWIM Clients                       │
                    │  (vNAS, CRC, SimAware, Virtual Airlines, etc.)     │
                    └─────────────────────────────────────────────────────┘

1.4 Cost Structure

Component Monthly Cost
SWIM_API Database (Azure SQL Basic) $5
WebSocket Server (self-hosted) $0
Total $5/month

2. Authentication

2.1 API Keys

All API requests require authentication via Bearer token or query parameter.

Header Authentication (Recommended):

Authorization: Bearer swim_dev_your_key_here

Query Parameter (WebSocket):

wss://perti.vatcscc.org/api/swim/v1/ws?api_key=swim_dev_your_key_here

2.2 API Key Tiers

Tier Prefix Rate Limit Max WS Connections Write Access
system swim_sys_ 30,000/min 10,000 Yes
partner swim_par_ 3,000/min 500 Limited
developer swim_dev_ 300/min 50 No
public swim_pub_ 100/min 5 No

2.3 Creating API Keys

API keys are stored in the dbo.swim_api_keys table in the SWIM_API database.

INSERT INTO dbo.swim_api_keys (api_key, tier, owner_name, owner_email, description)
VALUES (
    'swim_dev_' + LOWER(CONVERT(VARCHAR(36), NEWID())),
    'developer',
    'Developer Name',
    'email@example.com',
    'API key for development testing'
);

2.4 Key Validation

The system validates keys against the database with a 5-minute cache TTL:

  • Checks is_active = 1
  • Checks expires_at is null or in the future
  • Updates last_used_at on successful authentication

3. REST API Endpoints

3.1 API Index

Endpoint: GET /api/swim/v1

Returns API information and available endpoints.

Response:

{
  "success": true,
  "data": {
    "name": "VATSWIM API",
    "version": "1.0.0",
    "description": "System Wide Information Management for VATSIM",
    "documentation": "https://perti.vatcscc.org/docs/swim/",
    "endpoints": {
      "flights": {
        "GET /api/swim/v1/flights": "List flights with filters",
        "GET /api/swim/v1/flight": "Get single flight by GUFI or flight_key"
      },
      "positions": {
        "GET /api/swim/v1/positions": "Bulk flight positions (GeoJSON)"
      },
      "tmi": {
        "GET /api/swim/v1/tmi/programs": "Active TMI programs (GS/GDP)",
        "GET /api/swim/v1/tmi/controlled": "Flights under TMI control"
      }
    }
  }
}

3.2 Flights List

Endpoint: GET /api/swim/v1/flights

Returns paginated list of flights with optional filtering.

Query Parameters:

Parameter Type Description
status string active (default), completed, or all
dept_icao string Comma-separated departure airports (e.g., KJFK,KLGA)
dest_icao string Comma-separated destination airports
artcc string Comma-separated ARTCCs (e.g., ZNY,ZBW)
callsign string Callsign pattern with * wildcards (e.g., UAL*)
tmi_controlled boolean true to filter TMI-controlled flights
phase string Flight phase filter (e.g., ENROUTE,DESCENDING)
format string Response format (see below)
page int Page number (default: 1)
per_page int Results per page (default: 100, max: 1000)

Supported Formats:

Format Content-Type Description
json application/json Standard JSON with snake_case fields (default)
fixm application/json JSON with FIXM 4.3.0 camelCase field names
xml application/xml XML format for enterprise/SOAP integrations
geojson application/geo+json GeoJSON FeatureCollection for mapping (Leaflet, Mapbox)
csv text/csv CSV for spreadsheet/analytics export
kml application/vnd.google-earth.kml+xml KML for Google Earth visualization
ndjson application/x-ndjson Newline-delimited JSON for streaming/bulk processing

Example Request:

curl -H "Authorization: Bearer YOUR_API_KEY" \
  "https://perti.vatcscc.org/api/swim/v1/flights?dest_icao=KJFK&status=active"

Response (Legacy Format):

{
  "success": true,
  "data": [
    {
      "gufi": "VAT-20260116-UAL123-KLAX-KJFK",
      "flight_uid": 12345,
      "flight_key": "UAL123_KLAX_KJFK_20260116",
      "identity": {
        "callsign": "UAL123",
        "cid": 1234567,
        "aircraft_type": "B738",
        "aircraft_icao": "B738",
        "weight_class": "L",
        "wake_category": "M",
        "airline_icao": "UAL",
        "airline_name": "United Airlines"
      },
      "flight_plan": {
        "departure": "KLAX",
        "destination": "KJFK",
        "alternate": "KEWR",
        "cruise_altitude": 35000,
        "cruise_speed": 450,
        "route": "DOTSS5 KAYOH J146 ABQ J80 HVE J100 STL J24 JHW LENDY5",
        "flight_rules": "I",
        "departure_artcc": "ZLA",
        "destination_artcc": "ZNY",
        "arrival_fix": "LENDY",
        "arrival_procedure": "LENDY5"
      },
      "position": {
        "latitude": 40.1234,
        "longitude": -74.5678,
        "altitude_ft": 35000,
        "heading": 85,
        "ground_speed_kts": 480,
        "vertical_rate_fpm": 0,
        "current_artcc": "ZNY"
      },
      "progress": {
        "phase": "ENROUTE",
        "is_active": true,
        "distance_remaining_nm": 125.4,
        "pct_complete": 95.2,
        "time_to_dest_min": 15.7
      },
      "times": {
        "eta": "2026-01-16T18:45:00Z",
        "eta_runway": "2026-01-16T18:52:00Z",
        "out": "2026-01-16T14:05:00Z",
        "off": "2026-01-16T14:18:00Z"
      },
      "tmi": {
        "is_controlled": false,
        "ground_stop_held": false
      }
    }
  ],
  "pagination": {
    "total": 156,
    "page": 1,
    "per_page": 100,
    "total_pages": 2,
    "has_more": true
  },
  "timestamp": "2026-01-16T18:30:00Z"
}

3.3 Single Flight

Endpoint: GET /api/swim/v1/flight

Returns a single flight by GUFI or flight_key.

Query Parameters:

Parameter Type Description
gufi string Globally Unique Flight Identifier
flight_key string ADL flight key
format string legacy or fixm

3.4 Positions (GeoJSON)

Endpoint: GET /api/swim/v1/positions

Returns bulk flight positions in GeoJSON FeatureCollection format.

Query Parameters:

Parameter Type Description
dept_icao string Departure airport filter
dest_icao string Destination airport filter
artcc string ARTCC filter
bounds string Bounding box: minLon,minLat,maxLon,maxLat
tmi_controlled boolean TMI-controlled flights only
phase string Flight phase filter
include_route boolean Include route string in properties

Example Response:

{
  "type": "FeatureCollection",
  "features": [
    {
      "type": "Feature",
      "id": 12345,
      "geometry": {
        "type": "Point",
        "coordinates": [-74.5678, 40.1234, 35000]
      },
      "properties": {
        "flight_uid": 12345,
        "callsign": "UAL123",
        "aircraft": "B738",
        "departure": "KLAX",
        "destination": "KJFK",
        "phase": "ENROUTE",
        "altitude": 35000,
        "heading": 85,
        "groundspeed": 480,
        "distance_remaining_nm": 125.4,
        "tmi_status": "none"
      }
    }
  ],
  "metadata": {
    "count": 2847,
    "timestamp": "2026-01-16T18:30:00Z",
    "source": "vatcscc"
  }
}

3.5 TMI Programs

Endpoint: GET /api/swim/v1/tmi/programs

Returns active Traffic Management Initiatives (Ground Stops, GDPs).

Query Parameters:

Parameter Type Description
type string all (default), gs, or gdp
airport string Airport ICAO filter
artcc string ARTCC filter
include_history boolean Include recently ended programs

Example Response:

{
  "success": true,
  "data": {
    "ground_stops": [
      {
        "type": "ground_stop",
        "airport": "KJFK",
        "airport_name": "John F Kennedy Intl",
        "artcc": "ZNY",
        "reason": "Thunderstorms",
        "probability_of_extension": 60,
        "times": {
          "start": "2026-01-16T17:00:00Z",
          "end": "2026-01-16T19:00:00Z"
        },
        "is_active": true
      }
    ],
    "gdp_programs": [
      {
        "type": "gdp",
        "program_id": "GDP_KEWR_20260116",
        "airport": "KEWR",
        "airport_name": "Newark Liberty Intl",
        "artcc": "ZNY",
        "reason": "Volume",
        "rates": {"program_rate": 40},
        "delays": {
          "limit_minutes": 90,
          "average_minutes": 45,
          "maximum_minutes": 87
        },
        "flights": {
          "total": 156,
          "affected": 89
        },
        "is_active": true
      }
    ],
    "summary": {
      "active_ground_stops": 1,
      "active_gdp_programs": 1,
      "total_controlled_airports": 2
    }
  }
}

3.6 TMI Controlled Flights

Endpoint: GET /api/swim/v1/tmi/controlled

Returns flights currently under TMI control.

3.7 ADL Flight Ingest

Endpoint: POST /api/swim/v1/ingest/adl

Receives flight data from authoritative sources. Requires write access (system or partner tier).

Maximum batch size: 500 flights per request

Request Body:

{
  "flights": [
    {
      "callsign": "UAL123",
      "dept_icao": "KJFK",
      "dest_icao": "KLAX",
      "cid": 1234567,
      "aircraft_type": "B738",
      "route": "DCT JFK J584 ORD J64 LAX",
      "phase": "ENROUTE",
      "is_active": true,
      "latitude": 40.1234,
      "longitude": -74.5678,
      "altitude_ft": 35000,
      "heading_deg": 270,
      "groundspeed_kts": 450,
      "vertical_rate_fpm": -500,
      "out_utc": "2026-01-16T14:05:00Z",
      "off_utc": "2026-01-16T14:18:00Z",
      "eta_utc": "2026-01-16T18:45:00Z",
      "tmi": {
        "ctl_type": "GDP",
        "slot_time_utc": "2026-01-16T18:30:00Z",
        "delay_minutes": 45
      }
    }
  ]
}

Response:

{
  "success": true,
  "data": {
    "processed": 1,
    "created": 0,
    "updated": 1,
    "errors": 0,
    "error_details": []
  },
  "timestamp": "2026-01-16T12:00:00Z",
  "meta": {
    "source": "vatcscc",
    "batch_size": 1
  }
}

3.8 Track Position Ingest

Endpoint: POST /api/swim/v1/ingest/track

Receives real-time track/position updates from authoritative sources (vNAS, CRC, EuroScope, AOC systems).

Maximum batch size: 1000 tracks per request (higher limit for frequent position updates)

Request Body:

{
  "tracks": [
    {
      "callsign": "UAL123",
      "latitude": 40.6413,
      "longitude": -73.7781,
      "altitude_ft": 35000,
      "ground_speed_kts": 450,
      "heading_deg": 270,
      "vertical_rate_fpm": -500,
      "squawk": "1200",
      "track_source": "radar"
    }
  ]
}

Track Fields:

Field Type Required Description
callsign string Yes Aircraft callsign
latitude number Yes Latitude (-90 to 90)
longitude number Yes Longitude (-180 to 180)
altitude_ft integer No Altitude in feet MSL
ground_speed_kts integer No Ground speed in knots
heading_deg integer No Heading (0-360)
vertical_rate_fpm integer No Vertical rate (+ = climb, - = descend)
squawk string No Transponder code (4 digits)
track_source string No radar, ads-b, mlat, mode-s, acars
timestamp datetime No Observation time (ISO 8601)

Response:

{
  "success": true,
  "data": {
    "processed": 100,
    "updated": 95,
    "not_found": 5,
    "errors": 0,
    "error_details": []
  },
  "timestamp": "2026-01-16T12:00:00Z",
  "meta": {
    "source": "vnas",
    "batch_size": 100
  }
}

Notes:

  • Tracks are matched by callsign to existing active flights
  • Flights not found are skipped (not_found count) but not considered errors
  • Use this endpoint for high-frequency position updates from radar/ADS-B systems

3.9 Metering Data

Endpoint: GET /api/swim/v1/metering/{airport}

Returns TBFM-style metering data for arrivals to an airport.

Path Parameters:

Parameter Type Description
airport string Destination airport ICAO code (e.g., KJFK)

Query Parameters:

Parameter Type Description
status string Filter by metering status: UNMETERED, METERED, FROZEN, SUSPENDED, EXEMPT
runway string Filter by arrival runway (e.g., 31L)
stream string Filter by arrival stream/corner post
metered_only boolean Only return flights with metering data (default: true)
format string Response format: json, fixm, xml, csv, ndjson

Example Response:

{
  "success": true,
  "data": {
    "airport": "KJFK",
    "type": "metering_data",
    "flights": [
      {
        "gufi": "VAT-20260116-UAL123-KORD-KJFK",
        "callsign": "UAL123",
        "sequence_number": 5,
        "scheduled_time_of_arrival": "2026-01-16T18:30:00Z",
        "metering_time": "2026-01-16T18:15:00Z",
        "metering_delay": 5,
        "metering_frozen": true,
        "metering_status": "METERED",
        "arrival_stream": "NORTH",
        "arr_runway": "31L"
      }
    ],
    "count": 15,
    "summary": {
      "total": 15,
      "metered": 12,
      "frozen": 3,
      "avg_delay_minutes": 4.2
    }
  }
}

Sequence Endpoint: GET /api/swim/v1/metering/{airport}/sequence

Returns a compact arrival sequence list sorted by sequence number, optimized for datablock display.

3.10 Metering Ingest

Endpoint: POST /api/swim/v1/ingest/metering

Receives TBFM-style metering data from authoritative sources (SimTraffic, vATCSCC).

Maximum batch size: 500 metering records per request

Request Body:

{
  "airport": "KJFK",
  "metering_point": "CAMRN",
  "metering": [
    {
      "callsign": "UAL123",
      "sequence_number": 5,
      "scheduled_time_of_arrival": "2026-01-16T18:30:00Z",
      "metering_time": "2026-01-16T18:15:00Z",
      "metering_delay": 5,
      "metering_frozen": true,
      "arrival_stream": "NORTH",
      "arrival_runway": "31L",
      "metering_status": "METERED"
    }
  ]
}

Response:

{
  "success": true,
  "data": {
    "processed": 10,
    "updated": 8,
    "not_found": 2,
    "errors": 0
  },
  "meta": {
    "source": "simtraffic",
    "airport": "KJFK",
    "metering_point": "CAMRN"
  }
}

3.11 TMI Reroutes

Endpoint: GET /api/swim/v1/tmi/reroutes

Returns reroute definitions for Traffic Management Initiatives.

Query Parameters:

Parameter Type Description
status string Filter by status (comma-separated): 0=Draft, 1=Proposed, 2=Active, 3=Monitoring, 4=Expired, 5=Cancelled
active string If 1, returns only active reroutes (status 1,2,3)
limit int Maximum results (default: 100)
offset int Pagination offset

Example Response:

{
  "status": "ok",
  "total": 5,
  "counts": {
    "Active": 2,
    "Proposed": 1,
    "Monitoring": 2
  },
  "reroutes": [
    {
      "id": 1,
      "status": 2,
      "status_label": "Active",
      "name": "KJFK_WX_REROUTE",
      "adv_number": "ADV-2026-001",
      "start_utc": "2026-01-16T14:00:00",
      "end_utc": "2026-01-16T20:00:00",
      "protected_fixes": "CAMRN,PARCH",
      "avoid_fixes": "LENDY",
      "dest_airports": "KJFK",
      "dest_centers": "ZNY"
    }
  ]
}

3.12 Unified TMI Measures

Endpoint: GET /api/swim/v1/tmi/measures

Returns ALL traffic management measures from both USA (vATCSCC) and external providers (ECFMP, NavCanada, VATPAC) in a unified TFMS/FIXM-aligned format.

Query Parameters:

Parameter Type Description
provider string Filter by provider: vATCSCC, ECFMP, etc. (comma-separated)
type string Measure type: GS, GDP, AFP, MIT, MINIT, MDI, RATE, REROUTE
airport string Control element filter (comma-separated ICAO codes)
source string usa (vATCSCC only), external (non-USA), or all (default)
active_only boolean Filter to active measures only (default: true)
page int Page number (default: 1)
per_page int Results per page (default: 100, max: 1000)

Example Request:

curl -H "Authorization: Bearer YOUR_API_KEY" \
  "https://perti.vatcscc.org/api/swim/v1/tmi/measures?type=MIT,GS&active_only=true"

Example Response:

{
  "success": true,
  "data": {
    "measures": [
      {
        "id": "USA-45",
        "guid": "a1b2c3d4-...",
        "provider": {
          "code": "vATCSCC",
          "name": "VATSIM Command Center (USA)"
        },
        "ident": "GS_KJFK_45",
        "type": "GS",
        "value": null,
        "unit": null,
        "controlElement": "KJFK",
        "elementType": "APT",
        "reason": "Thunderstorms",
        "filters": {
          "arrivalAerodrome": ["KJFK"]
        },
        "timeRange": {
          "start": "2026-01-17T18:00:00Z",
          "end": "2026-01-17T20:00:00Z"
        },
        "status": "ACTIVE",
        "_source": "usa"
      },
      {
        "id": "ECFMP-456",
        "guid": "e5f6g7h8-...",
        "provider": {
          "code": "ECFMP",
          "name": "EUROCONTROL Flow Management"
        },
        "ident": "EGTT22A",
        "type": "MDI",
        "value": 120,
        "unit": "SEC",
        "reason": "CTP Event Traffic",
        "event": {
          "id": 123,
          "code": "CTP2026",
          "name": "Cross the Pond 2026"
        },
        "filters": {
          "departureAerodrome": ["KJFK", "KEWR"],
          "arrivalAerodrome": ["EGLL", "EGKK"]
        },
        "exemptions": {
          "eventFlights": true
        },
        "timeRange": {
          "start": "2026-03-15T12:00:00Z",
          "end": "2026-03-15T20:00:00Z"
        },
        "status": "ACTIVE",
        "_source": "external"
      }
    ],
    "statistics": {
      "by_provider": { "vATCSCC": 5, "ECFMP": 3 },
      "by_type": { "GS": 2, "MIT": 3, "MDI": 2, "GDP": 1 },
      "by_source": { "usa": 5, "external": 3 }
    },
    "pagination": {
      "total": 8,
      "page": 1,
      "per_page": 100
    }
  }
}

3.13 External Flow Management

Provider-agnostic integration for external flow management systems. Supports ECFMP (Europe/NAT), NavCanada, VATPAC, and future regional providers.

3.13.1 Flow Index

Endpoint: GET /api/swim/v1/tmi/flow/

Returns overview of external flow management endpoints and active counts.

3.13.2 Flow Providers

Endpoint: GET /api/swim/v1/tmi/flow/providers

Returns registered external flow management providers.

Query Parameters:

Parameter Type Description
provider string Filter by provider code
region string Filter by region: EUR, NAM, NAT, PAC
active_only boolean Filter to active providers only (default: true)

Example Response:

{
  "success": true,
  "data": {
    "providers": [
      {
        "id": 1,
        "code": "ECFMP",
        "name": "EUROCONTROL Flow Management",
        "api": {
          "base_url": "https://ecfmp.vatsim.net/api/v1",
          "version": "v1"
        },
        "coverage": {
          "regions": ["EUR", "NAT"],
          "firs": ["EGTT", "EGPX", "CZQX"]
        },
        "sync": {
          "enabled": true,
          "interval_sec": 300,
          "last_sync_utc": "2026-01-17T15:30:00Z",
          "last_status": "SUCCESS"
        },
        "is_active": true
      }
    ]
  }
}

3.13.3 Flow Events

Endpoint: GET /api/swim/v1/tmi/flow/events

Returns special events (CTP, FNO, etc.) from external providers.

Query Parameters:

Parameter Type Description
provider string Filter by provider: ECFMP, NAVCAN, etc.
code string Event code filter: CTP2026, FNO2026
status string Status filter: SCHEDULED, ACTIVE, COMPLETED
include_participants boolean Include participant list (default: false)

Example Response:

{
  "success": true,
  "data": {
    "events": [
      {
        "id": 123,
        "guid": "abc123...",
        "provider": { "code": "ECFMP", "name": "EUROCONTROL Flow Management" },
        "code": "CTP2026",
        "name": "Cross the Pond 2026",
        "type": "SPECIAL",
        "firs": ["EGTT", "EGPX", "CZQX", "KZNY"],
        "timeRange": {
          "start": "2026-03-15T12:00:00Z",
          "end": "2026-03-15T20:00:00Z"
        },
        "exemptions": {
          "groundStop": true,
          "gdpPriority": true
        },
        "status": "SCHEDULED",
        "participantCount": 1247
      }
    ]
  }
}

3.13.4 Flow Measures

Endpoint: GET /api/swim/v1/tmi/flow/measures

Returns flow measures (MIT, MINIT, MDI, etc.) from external providers only.

Query Parameters:

Parameter Type Description
provider string Filter by provider
type string Measure type: MIT, MINIT, MDI, RATE, GS, REROUTE
event_id int Filter by associated event
airport string Filter by control element
active_only boolean Filter to active measures (default: true)

Measure Types (TFMS-aligned):

Type Description Unit
MIT Miles-In-Trail NM
MINIT Minutes-In-Trail MIN
MDI Minimum Departure Interval SEC
RATE Departure Rate Cap PER_HOUR
GS Ground Stop -
GDP Ground Delay Program MIN
AFP Airspace Flow Program MIN
REROUTE Mandatory Reroute -

Example Response:

{
  "success": true,
  "data": {
    "measures": [
      {
        "id": 456,
        "ident": "EGTT22A",
        "provider": { "code": "ECFMP" },
        "type": "MDI",
        "value": 120,
        "unit": "SEC",
        "event": { "id": 123, "code": "CTP2026" },
        "reason": "CTP Event Traffic",
        "filters": {
          "departureAerodrome": ["KJFK", "KEWR", "KLGA"],
          "arrivalAerodrome": ["EGLL", "EGKK"]
        },
        "exemptions": {
          "eventFlights": true
        },
        "mandatoryRoute": ["KJFK", "MERIT", "NAT-A", "EGLL"],
        "timeRange": {
          "start": "2026-03-15T12:00:00Z",
          "end": "2026-03-15T20:00:00Z"
        },
        "status": "ACTIVE"
      }
    ]
  }
}

3.14 JATOC Incidents

Endpoint: GET /api/swim/v1/jatoc/incidents

Returns JATOC (Joint Air Traffic Operations Center) incident records.

Query Parameters:

Parameter Type Description
lifecycle_status string Filter: OPEN, IN_PROGRESS, RESOLVED, CLOSED
facility string Filter by facility (partial match)
facilities string Filter by multiple facilities (comma-separated, exact match)
facility_type string Filter: ARTCC, TRACON, ATCT, FSS
limit int Results per page (default: 50, max: 100)
offset int Pagination offset

Example Response:

{
  "success": true,
  "data": [
    {
      "id": 1,
      "incident_number": "2026-001",
      "facility": "KJFK",
      "facility_type": "ATCT",
      "incident_type": "EQUIPMENT",
      "lifecycle_status": "RESOLVED",
      "severity": "MEDIUM",
      "summary": "Primary radar outage",
      "start_utc": "2026-01-16T14:00:00",
      "end_utc": "2026-01-16T15:30:00"
    }
  ],
  "pagination": {
    "total": 45,
    "limit": 50,
    "offset": 0,
    "page": 1
  }
}

3.15 Route Resolution

Resolves route strings into fully processed waypoints with coordinates, distances, and ARTCC traversal using PostGIS spatial analysis. Supports airway expansion, oceanic coordinate parsing, fix disambiguation, and duplicate filtering.

GET /api/swim/v1/routes/resolve

Resolves a single route string.

Query Parameters:

Parameter Type Required Description
route_string string Yes Route string to resolve (e.g., DOTSS5 KAYOH J146 ABQ)
origin string No Origin airport ICAO code — auto-prepended if not already the first token
dest string No Destination airport ICAO code — auto-appended if not already the last token

Example Request:

curl -H "Authorization: Bearer YOUR_API_KEY" \
  "https://perti.vatcscc.org/api/swim/v1/routes/resolve?route_string=GAYEL+Q818+WOZEE+KENPA+OBSTR+WYNDE3&origin=KJFK&dest=KORD"

Response:

{
  "success": true,
  "data": {
    "route_string": "GAYEL Q818 WOZEE KENPA OBSTR WYNDE3",
    "expanded_route": "KJFK GAYEL MSLIN STOMP BUFFY CFB VIEEW KELIE WOZEE KENPA OBSTR KORD",
    "origin": "KJFK",
    "dest": "KORD",
    "total_distance_nm": 758.6,
    "waypoint_count": 12,
    "waypoints": [
      {"seq": 1, "fix": "KJFK", "lat": 40.639928, "lon": -73.778692, "type": "nav_fix"},
      {"seq": 2, "fix": "GAYEL", "lat": 41.406692, "lon": -74.357144, "type": "nav_fix"},
      {"seq": 3, "fix": "MSLIN", "lat": 41.491894, "lon": -74.553967, "type": "airway_Q818"},
      {"seq": 4, "fix": "STOMP", "lat": 41.596328, "lon": -74.796608, "type": "airway_Q818"},
      {"seq": 5, "fix": "BUFFY", "lat": 41.941108, "lon": -75.6126, "type": "airway_Q818"},
      {"seq": 6, "fix": "CFB", "lat": 42.15749, "lon": -76.136472, "type": "airway_Q818"},
      {"seq": 7, "fix": "VIEEW", "lat": 42.439464, "lon": -77.025917, "type": "airway_Q818"},
      {"seq": 8, "fix": "KELIE", "lat": 42.660367, "lon": -77.744736, "type": "airway_Q818"},
      {"seq": 9, "fix": "WOZEE", "lat": 42.933792, "lon": -78.738789, "type": "airway_Q818"},
      {"seq": 10, "fix": "KENPA", "lat": 44.795, "lon": -82.393333, "type": "nav_fix"},
      {"seq": 11, "fix": "OBSTR", "lat": 43.695056, "lon": -85.214869, "type": "nav_fix"},
      {"seq": 12, "fix": "KORD", "lat": 41.9786, "lon": -87.9048, "type": "nav_fix"}
    ],
    "artccs_traversed": ["ZNY", "ZOB", "CZYZ", "ZMP", "ZAU"]
  }
}

Response Fields:

Field Type Description
route_string string The original route string as submitted
expanded_route string Space-separated resolved fix names (after airway expansion)
origin string Origin airport ICAO (if provided)
dest string Destination airport ICAO (if provided)
total_distance_nm float Total route distance in nautical miles
waypoint_count int Number of resolved waypoints
waypoints array Ordered waypoints with seq, fix, lat, lon, type
artccs_traversed array ARTCC codes traversed by the route (K-prefix stripped)

Waypoint type Values:

Type Description
nav_fix Named fix, intersection, navaid, or airport
airway_{name} Fix expanded from an airway (e.g., airway_Q818, airway_J60)
coordinate Oceanic lat/lon waypoint (e.g., parsed from 41N060W or 45/73)

POST /api/swim/v1/routes/resolve (Batch Mode)

Resolves up to 50 route strings in a single request. Uses a single PostGIS expand_routes_batch() call for efficiency. Each route is resolved independently — a failure in one route does not affect others.

Maximum batch size: 50 routes per request

Request Body:

{
  "routes": [
    {
      "route_string": "GAYEL Q818 WOZEE KENPA OBSTR WYNDE3",
      "origin": "KJFK",
      "dest": "KORD"
    },
    {
      "route_string": "BADROUTE INVALID",
      "origin": "KJFK",
      "dest": "KLAX"
    }
  ]
}

Route Item Fields:

Field Type Required Description
route_string string Yes Route string to resolve
origin string No Origin airport — auto-prepended if missing from route
dest string No Destination airport — auto-appended if missing from route

Response:

{
  "success": true,
  "data": {
    "count": 2,
    "routes": [
      {
        "route_string": "GAYEL Q818 WOZEE KENPA OBSTR WYNDE3",
        "expanded_route": "KJFK GAYEL MSLIN STOMP BUFFY CFB VIEEW KELIE WOZEE KENPA OBSTR KORD",
        "origin": "KJFK",
        "dest": "KORD",
        "total_distance_nm": 758.6,
        "waypoint_count": 12,
        "waypoints": [
          {"seq": 1, "fix": "KJFK", "lat": 40.639928, "lon": -73.778692, "type": "nav_fix"},
          {"seq": 2, "fix": "GAYEL", "lat": 41.406692, "lon": -74.357144, "type": "nav_fix"}
        ],
        "artccs_traversed": ["ZNY", "ZOB", "CZYZ", "ZMP", "ZAU"]
      },
      {
        "route_string": "BADROUTE INVALID",
        "expanded_route": "KJFK KLAX",
        "origin": "KJFK",
        "dest": "KLAX",
        "total_distance_nm": 2150.6,
        "waypoint_count": 2,
        "waypoints": [
          {"seq": 1, "fix": "KJFK", "lat": 40.639928, "lon": -73.778692, "type": "nav_fix"},
          {"seq": 2, "fix": "KLAX", "lat": 33.942501, "lon": -118.407997, "type": "nav_fix"}
        ],
        "artccs_traversed": ["ZNY", "ZOB", "ZID", "ZKC", "ZAB", "ZLA"]
      }
    ]
  }
}

Notes:

  • Failed routes include an error field instead of waypoint data
  • The origin and dest bookends are only prepended/appended if the route string doesn't already start/end with that token
  • ARTCC codes are normalized (K-prefix stripped: KZNYZNY)

Error Responses:

Code When
400 Missing route_string, empty routes array, or batch limit exceeded
401 Invalid or missing API key
405 Non-GET/POST method used
503 PostGIS service unavailable

3.16 Runway Configuration Presets

Endpoint: GET /api/swim/v1/splits/presets

Returns saved runway configuration presets.

Query Parameters:

Parameter Type Description
artcc string Filter by ARTCC
airport string Filter by airport
id int Get single preset by ID

Example Response:

{
  "success": true,
  "presets": [
    {
      "id": 1,
      "name": "KJFK_ILS31L_VIS31R",
      "artcc": "ZNY",
      "airport": "KJFK",
      "description": "ILS 31L arrivals, Visual 31R departures",
      "is_default": false,
      "positions": [
        {"runway": "31L", "operation": "ARR", "is_primary": true, "rate": 40},
        {"runway": "31R", "operation": "DEP", "is_primary": true, "rate": 45}
      ]
    }
  ]
}

4. WebSocket Real-Time API

4.1 Connection

Connect to the WebSocket server with your API key:

const ws = new WebSocket('wss://perti.vatcscc.org/api/swim/v1/ws?api_key=YOUR_KEY');

Connection Response:

{
  "type": "connected",
  "data": {
    "client_id": "c_abc123def456",
    "server_time": "2026-01-16T18:30:00Z",
    "version": "1.0.0"
  }
}

4.2 Subscribing to Events

Send a subscribe message to receive specific event types:

{
  "action": "subscribe",
  "channels": ["flight.departed", "flight.arrived", "tmi.issued"],
  "filters": {
    "airports": ["KJFK", "KLGA", "KEWR"],
    "artccs": ["ZNY"]
  }
}

Available Channels:

Channel Description
flight.created New pilot connected to network
flight.departed Aircraft wheels-up (OFF time set)
flight.arrived Aircraft wheels-down (IN time set)
flight.deleted Pilot disconnected
flight.positions Batched position updates
flight.* All flight events
tmi.issued New Ground Stop/GDP created
tmi.released TMI ended/released
tmi.* All TMI events
system.heartbeat Server keepalive (30s interval)

Subscription Filters:

Filter Type Description
airports array ICAO codes to filter by departure/destination
artccs array ARTCC IDs to filter
callsign_prefix array Callsign prefixes (e.g., ["UAL", "DAL"])
bbox object Geographic bounding box {north, south, east, west}

4.3 Event Formats

flight.departed:

{
  "type": "flight.departed",
  "timestamp": "2026-01-16T18:30:15.123Z",
  "data": {
    "callsign": "UAL123",
    "flight_uid": 12345,
    "dep": "KLAX",
    "arr": "KJFK",
    "off_utc": "2026-01-16T18:30:00Z"
  }
}

flight.arrived:

{
  "type": "flight.arrived",
  "timestamp": "2026-01-16T22:45:30.456Z",
  "data": {
    "callsign": "UAL123",
    "flight_uid": 12345,
    "dep": "KLAX",
    "arr": "KJFK",
    "in_utc": "2026-01-16T22:45:00Z"
  }
}

flight.positions (batched):

{
  "type": "flight.positions",
  "timestamp": "2026-01-16T18:30:15.123Z",
  "data": {
    "count": 2847,
    "positions": [
      {
        "callsign": "UAL123",
        "flight_uid": 12345,
        "latitude": 40.1234,
        "longitude": -74.5678,
        "altitude_ft": 35000,
        "groundspeed_kts": 480,
        "heading_deg": 85,
        "vertical_rate_fpm": 0,
        "current_artcc": "ZNY",
        "dep": "KLAX",
        "arr": "KJFK"
      }
    ]
  }
}

tmi.issued:

{
  "type": "tmi.issued",
  "timestamp": "2026-01-16T17:00:00.000Z",
  "data": {
    "program_id": "GS_KJFK_20260116",
    "program_type": "GROUND_STOP",
    "airport": "KJFK",
    "start_time": "2026-01-16T17:00:00Z",
    "end_time": "2026-01-16T19:00:00Z",
    "reason": "Thunderstorms"
  }
}

system.heartbeat:

{
  "type": "system.heartbeat",
  "timestamp": "2026-01-16T18:30:00Z",
  "data": {
    "connected_clients": 47,
    "uptime_seconds": 86400
  }
}

4.4 Client Actions

Ping:

{"action": "ping"}

Response: {"type": "pong", "timestamp": "..."}

Status:

{"action": "status"}

Returns current subscriptions and message counts.

Unsubscribe:

{
  "action": "unsubscribe",
  "channels": ["flight.positions"]
}

4.5 Error Handling

{
  "type": "error",
  "code": "AUTH_FAILED",
  "message": "Invalid or missing API key"
}

Error Codes:

Code Description
AUTH_FAILED Invalid or expired API key
CONNECTION_LIMIT Tier connection limit reached
RATE_LIMITED Too many messages per second
INVALID_JSON Malformed JSON message
INVALID_CHANNEL Unknown channel name
INVALID_FILTER Invalid filter specification
MESSAGE_TOO_LARGE Message exceeds 64KB limit

5. Data Models

5.1 GUFI (Globally Unique Flight Identifier)

Format: VAT-YYYYMMDD-CALLSIGN-DEPT-DEST

Example: VAT-20260116-UAL123-KLAX-KJFK

Generation:

function swim_generate_gufi($callsign, $dept_icao, $dest_icao, $date = null) {
    if ($date === null) $date = gmdate('Ymd');
    return implode('-', ['VAT', $date, strtoupper($callsign), 
                         strtoupper($dept_icao), strtoupper($dest_icao)]);
}

5.2 Flight Phases

Phase Description
PREFLIGHT Connected, not yet departed
DEPARTING Taxiing for departure
CLIMBING Airborne, climbing
ENROUTE Cruise altitude
DESCENDING Descending to destination
APPROACH On approach
LANDED Wheels down, taxiing
ARRIVED At gate/parked

5.3 TMI Control Types

Type Description
GS Ground Stop
GDP Ground Delay Program
MIT Miles-in-Trail
MINIT Minutes-in-Trail
AFP Airspace Flow Program

5.4 AOC Telemetry Fields

Virtual Airlines and flight simulator integrations can push telemetry data via the ADL ingest endpoint.

OOOI Times (Out/Off/On/In):

Field Description Source
out_utc Gate departure (pushback) AOC/ACARS
off_utc Wheels up (takeoff) AOC/ACARS
on_utc Wheels down (landing) AOC/ACARS
in_utc Gate arrival AOC/ACARS

FMC Times:

Field Description Source
eta_utc Estimated time of arrival FMC/AOC
etd_utc Estimated time of departure FMC/AOC

Position Telemetry:

Field Description Source
vertical_rate_fpm Climb/descent rate (ft/min) Flight sim
latitude Current position Flight sim
longitude Current position Flight sim
altitude_ft Current altitude (MSL) Flight sim
heading_deg Current heading Flight sim
groundspeed_kts Ground speed Flight sim

Example: Virtual Airline PIREP Integration

{
  "flights": [
    {
      "callsign": "VPA123",
      "dept_icao": "KJFK",
      "dest_icao": "KLAX",
      "cid": 1234567,
      "out_utc": "2026-01-16T14:05:00Z",
      "off_utc": "2026-01-16T14:18:00Z",
      "latitude": 40.1234,
      "longitude": -98.5678,
      "altitude_ft": 35000,
      "groundspeed_kts": 485,
      "vertical_rate_fpm": 0,
      "eta_utc": "2026-01-16T18:45:00Z"
    }
  ]
}

Data Authority Rules:

The telemetry data source must be authorized to write the field:

  • SIMULATOR source: Authoritative for telemetry fields, can override
  • VIRTUAL_AIRLINE source: Authoritative for airline fields
  • Other sources cannot write telemetry fields unless explicitly allowed

5.5 FIXM Field Mapping

The API supports both legacy and FIXM-aligned field names via the ?format=fixm parameter.

Legacy Name FIXM Name
callsign aircraft_identification
departure departure_aerodrome
destination arrival_aerodrome
cruise_altitude cruising_level
heading track
ground_speed_kts ground_speed
altitude_ft altitude
phase flight_status
wake_category wake_turbulence
airline_icao operator_icao
out actual_off_block_time
off actual_time_of_departure
on actual_landing_time
in actual_in_block_time

6. Python SDK

6.1 Installation

cd PERTI/sdk/python
pip install -e .

Or install directly:

pip install websockets

6.2 Basic Usage

from swim_client import SWIMClient

# Create client
client = SWIMClient('swim_dev_your_key', debug=True)

# Handle events with decorators
@client.on('connected')
def on_connected(info, timestamp):
    print(f"Connected! Client ID: {info.client_id}")

@client.on('flight.departed')
def on_departure(event, timestamp):
    print(f"{event.callsign} departed {event.dep}")

@client.on('flight.arrived')
def on_arrival(event, timestamp):
    print(f"{event.callsign} arrived at {event.arr}")

@client.on('system.heartbeat')
def on_heartbeat(data, timestamp):
    print(f"Heartbeat: {data.connected_clients} clients")

# Subscribe to channels
client.subscribe([
    'flight.departed',
    'flight.arrived',
    'system.heartbeat'
])

# Run (blocking)
client.run()

6.3 Filtering

# Subscribe with airport filter
client.subscribe(
    channels=['flight.departed', 'flight.arrived'],
    airports=['KJFK', 'KLGA', 'KEWR'],
    artccs=['ZNY']
)

# Subscribe with bounding box
client.subscribe(
    channels=['flight.positions'],
    bbox={'north': 42.0, 'south': 39.0, 'east': -72.0, 'west': -76.0}
)

6.4 Async Usage

import asyncio
from swim_client import SWIMClient

async def main():
    client = SWIMClient('swim_dev_your_key')

    @client.on('flight.departed')
    def on_departure(event, timestamp):
        print(f"{event.callsign} departed")

    client.subscribe(['flight.departed'])

    await client.connect()
    await client.run_async()

asyncio.run(main())

6.5 SDK Configuration

Parameter Default Description
api_key required API key for authentication
url wss://perti.vatcscc.org/... WebSocket URL
reconnect True Auto-reconnect on disconnect
reconnect_interval 5.0 Initial reconnect delay (seconds)
max_reconnect_interval 60.0 Maximum reconnect delay
ping_interval 30.0 Ping interval (seconds)
debug False Enable debug logging

7. Configuration Reference

7.1 swim_config.php

Located at PERTI/load/swim_config.php

API Version:

define('SWIM_API_VERSION', '1.0.0');
define('SWIM_API_PREFIX', '/api/swim/v1');

Rate Limits:

$SWIM_RATE_LIMITS = [
    'system'    => 30000,
    'partner'   => 3000,
    'developer' => 300,
    'public'    => 100
];

Key Prefixes:

$SWIM_KEY_PREFIXES = [
    'system'    => 'swim_sys_',
    'partner'   => 'swim_par_',
    'developer' => 'swim_dev_',
    'public'    => 'swim_pub_'
];

Data Sources:

$SWIM_DATA_SOURCES = [
    // Core sources
    'VATSIM'          => 'vatsim',           // Identity and flight plans
    'vATCSCC'         => 'vatcscc',          // ADL, TMI, demand

    // Track/position sources
    'VNAS'            => 'vnas',             // Track data, ATC automation
    'CRC'             => 'crc',              // Track data, tags
    'EUROSCOPE'       => 'euroscope',        // Track data

    // ACARS sources
    'ACARS'           => 'acars',            // Generic ACARS (OOOI times)
    'HOPPIE'          => 'hoppie',           // Hoppie ACARS

    // Metering sources
    'SIMTRAFFIC'      => 'simtraffic',       // TBFM-style metering
    'TOPSKY'          => 'topsky',           // TopSky EuroScope AMAN

    // External sources
    'SIMBRIEF'        => 'simbrief',         // OFP data
    'SIMULATOR'       => 'simulator',        // Pilot sim telemetry
    'VIRTUAL_AIRLINE' => 'virtual_airline',  // VA AOC systems (schedules, CDM)

    // Future
    'VFDS'            => 'vfds',             // vFlightDataSystems
];

Source Priority Rankings (per FAA CDM spec):

Data Type Priority Order (highest first)
Track Position vNAS → CRC → EuroScope → simulator → ACARS
OOOI Times ACARS → Virtual Airline → simulator → vATCSCC
Schedule (STD/STA) Virtual Airline → SimBrief → vATCSCC
Metering SimTraffic → vATCSCC → vNAS → TopSky
General Times SimTraffic → vATCSCC → vNAS → vFDS → SimBrief → simulator

CDM Time Fields (FAA ADL T-Field Reference):

Field CDM Ref Description Authority
std_utc - Scheduled Time of Departure VA/SimBrief
sta_utc - Scheduled Time of Arrival VA/SimBrief
lrtd_utc T1 Airline Runway Time of Departure Virtual Airline
lrta_utc T2 Airline Runway Time of Arrival Virtual Airline
lgtd_utc T3 Airline Gate Time of Departure Virtual Airline
lgta_utc T4 Airline Gate Time of Arrival Virtual Airline
ertd_utc T7 Earliest Runway Time of Departure Virtual Airline
erta_utc T8 Earliest Runway Time of Arrival Virtual Airline
out_utc T13 Actual Off-Block (AOBT) ACARS/VA/sim
off_utc T11 Actual Takeoff (ATOT) ACARS/VA/sim
on_utc T12 Actual Landing (ALDT) ACARS/VA/sim
in_utc T14 Actual In-Block (AIBT) ACARS/VA/sim
edct_utc - Expected Departure Clearance Time vATCSCC only
ctd_utc - Controlled Time of Departure vATCSCC only
cta_utc - Controlled Time of Arrival vATCSCC only
tobt_utc - Target Off-Block Time vATCSCC only

Merge Behaviors:

Behavior Description
priority_based Higher priority source always wins (OOOI times)
immutable Only authoritative source can write (TMI, schedules)
variable Accepts newer timestamps (ETAs, metering)
monotonic Rejects older timestamps (position data)

Cache TTL:

$SWIM_CACHE_TTL = [
    'flights_list'   => 5,
    'flight_single'  => 3,
    'positions'      => 2,
    'tmi_programs'   => 10,
    'stats'          => 60
];

Pagination:

define('SWIM_DEFAULT_PAGE_SIZE', 100);
define('SWIM_MAX_PAGE_SIZE', 1000);
define('SWIM_GEOJSON_PRECISION', 5);

7.2 WebSocket Server Configuration

$config = [
    'auth_enabled' => true,
    'rate_limit_msg_per_sec' => 10,
    'heartbeat_interval' => 30,
    'max_message_size' => 65536,
    'allowed_origins' => ['*'],
    'debug' => false
];

Tier Connection Limits:

// WebSocket connection limits (unchanged)
$tierLimits = [
    'public' => 5,
    'developer' => 50,
    'partner' => 500,
    'system' => 10000
];

8. Database Schema

8.1 swim_api_keys

Stores API key credentials and permissions.

CREATE TABLE dbo.swim_api_keys (
    id INT IDENTITY(1,1) PRIMARY KEY,
    api_key NVARCHAR(64) NOT NULL UNIQUE,
    tier NVARCHAR(20) NOT NULL,  -- system, partner, developer, public
    owner_name NVARCHAR(100) NOT NULL,
    owner_email NVARCHAR(255),
    source_id NVARCHAR(50) NULL,
    can_write BIT NOT NULL DEFAULT 0,
    allowed_sources NVARCHAR(MAX) NULL,  -- JSON array
    ip_whitelist NVARCHAR(MAX) NULL,     -- JSON array
    description NVARCHAR(500) NULL,
    expires_at DATETIME2 NULL,
    created_at DATETIME2 NOT NULL DEFAULT GETUTCDATE(),
    last_used_at DATETIME2 NULL,
    is_active BIT NOT NULL DEFAULT 1
);

8.2 swim_audit_log

Request logging for monitoring and debugging.

CREATE TABLE dbo.swim_audit_log (
    id BIGINT IDENTITY(1,1) PRIMARY KEY,
    api_key_id INT NULL,
    endpoint NVARCHAR(255) NOT NULL,
    method NVARCHAR(10) NOT NULL,
    ip_address NVARCHAR(45) NOT NULL,
    user_agent NVARCHAR(500) NULL,
    response_status INT NULL,
    response_time_ms INT NULL,
    request_time DATETIME2 NOT NULL DEFAULT GETUTCDATE()
);

8.3 swim_subscriptions

WebSocket subscription tracking.

CREATE TABLE dbo.swim_subscriptions (
    id INT IDENTITY(1,1) PRIMARY KEY,
    api_key_id INT NOT NULL,
    connection_id NVARCHAR(64) NOT NULL,
    channels NVARCHAR(MAX) NOT NULL,     -- JSON array
    filters NVARCHAR(MAX) NULL,          -- JSON object
    connected_at DATETIME2 NOT NULL DEFAULT GETUTCDATE(),
    last_ping_at DATETIME2 NOT NULL DEFAULT GETUTCDATE(),
    is_active BIT NOT NULL DEFAULT 1,
    FOREIGN KEY (api_key_id) REFERENCES swim_api_keys(id)
);

8.4 swim_webhook_endpoints

Webhook registration for push notifications.

CREATE TABLE dbo.swim_webhook_endpoints (
    id INT IDENTITY(1,1) PRIMARY KEY,
    api_key_id INT NOT NULL,
    endpoint_url NVARCHAR(500) NOT NULL,
    events NVARCHAR(MAX) NOT NULL,       -- JSON array
    secret NVARCHAR(64) NOT NULL,        -- HMAC signing secret
    retry_count INT NOT NULL DEFAULT 3,
    timeout_seconds INT NOT NULL DEFAULT 30,
    last_delivery_at DATETIME2 NULL,
    failure_count INT NOT NULL DEFAULT 0,
    created_at DATETIME2 NOT NULL DEFAULT GETUTCDATE(),
    is_active BIT NOT NULL DEFAULT 1,
    FOREIGN KEY (api_key_id) REFERENCES swim_api_keys(id)
);

9. Deployment & Operations

9.1 File Structure

PERTI/
├── api/swim/v1/
│   ├── index.php              # API index
│   ├── auth.php               # Authentication middleware
│   ├── flights.php            # Flights endpoint
│   ├── flight.php             # Single flight endpoint
│   ├── positions.php          # GeoJSON positions
│   ├── routes/                # Route data endpoints
│   │   ├── resolve.php        # Route resolution (GET + batch POST)
│   │   └── cdrs.php           # Coded Departure Routes
│   ├── ingest/                # Data ingestion endpoints
│   │   ├── adl.php
│   │   └── track.php
│   ├── tmi/                   # TMI endpoints
│   │   ├── programs.php
│   │   └── controlled.php
│   └── ws/                    # WebSocket components
│       ├── WebSocketServer.php
│       ├── ClientConnection.php
│       ├── SubscriptionManager.php
│       └── swim-ws-client.js
├── scripts/
│   ├── swim_ws_server.php     # WebSocket daemon
│   ├── swim_ws_events.php     # Event detection
│   └── startup.sh             # Azure startup script
├── sdk/python/
│   ├── swim_client/
│   │   ├── __init__.py
│   │   ├── client.py
│   │   └── events.py
│   └── examples/
│       ├── basic_example.py
│       └── airport_monitor.py
├── load/
│   └── swim_config.php        # Configuration
└── database/migrations/swim/
    ├── 001_swim_tables.sql
    └── 002_swim_api_database.sql

9.2 Starting WebSocket Server

# Start daemon
nohup php /home/site/wwwroot/scripts/swim_ws_server.php --debug > /home/LogFiles/swim_ws.log 2>&1 &

# Check status
tail -f /home/LogFiles/swim_ws.log

# Restart
pkill -f swim_ws_server
rm -f /home/site/wwwroot/scripts/swim_ws.lock
nohup php /home/site/wwwroot/scripts/swim_ws_server.php --debug > /home/LogFiles/swim_ws.log 2>&1 &

9.3 Apache WebSocket Proxy

In startup.sh:

# Enable proxy modules
a2enmod proxy proxy_http proxy_wstunnel

# Add to Apache config
<Location /api/swim/v1/ws>
    ProxyPass ws://localhost:8090/
    ProxyPassReverse ws://localhost:8090/
</Location>

9.4 Monitoring

Check Connected Clients:

curl -H "Authorization: Bearer swim_sys_internal" \
  "https://perti.vatcscc.org/api/swim/v1/ws/stats"

Audit Log Cleanup:

EXEC dbo.sp_Swim_CleanupAuditLog @days_to_keep = 90;

10. Implementation Status

10.1 Phase Summary

Phase Status Progress
Phase 0: Infrastructure ✅ COMPLETE 100%
Phase 1: REST API ✅ COMPLETE 100%
Phase 2: WebSocket ✅ COMPLETE 100%
Phase 3: SDKs ✅ COMPLETE Python, C#, Java, JS

10.2 Completed Features

  • ✅ Azure SQL Basic database (SWIM_API) - $5/month
  • ✅ API key authentication with tier-based rate limits
  • ✅ All REST endpoints (flights, positions, TMI)
  • ✅ OpenAPI/Swagger documentation
  • ✅ Postman collection
  • ✅ FIXM field naming support
  • ✅ GeoJSON position output
  • ✅ Ratchet WebSocket server (port 8090)
  • ✅ External WSS via Apache proxy
  • ✅ Real-time event detection
  • ✅ Database authentication with key caching
  • ✅ Tier-based connection limits
  • ✅ Python SDK with async support
  • ✅ C# SDK (sdk/csharp/)
  • ✅ Java SDK (sdk/java/)
  • ✅ JavaScript SDK (api/swim/v1/ws/swim-ws-client.js)

10.3 Pending Features

Feature Priority Notes
Message compression Low Performance optimization
Historical replay Low Past event retrieval
Metrics dashboard Low Usage tracking
Redis caching Deferred File IPC adequate

10.4 Contact


Document generated from PERTI codebase analysis - March 2026