-
Notifications
You must be signed in to change notification settings - Fork 0
SWIM Route Data Integration
Use VATSWIM's pre-processed route data to get resolved waypoints, GeoJSON geometry, distances, and facility traversals without building your own navdata database or route parser.
API Base URL: https://perti.vatcscc.org/api/swim/v1
VATSWIM's route processing pipeline resolves raw route strings like KJFK GREKI JUDDS CAM J9 MLF ANJLL4 KLAX into:
| Output | Description |
|---|---|
| Waypoints | Ordered lat/lon coordinates for every fix on the route |
| GeoJSON LineString | Ready-to-render geometry for MapLibre / Leaflet / Mapbox |
| Distance | Calculated route distance in nautical miles |
| ARTCC Traversal | Ordered list of ATC centers the route passes through |
| TRACON/Sector Traversal | Terminal and sector boundary crossings |
This eliminates the need to maintain your own copy of 384K nav fixes, 17K airways, 90K airway segments, or write disambiguation logic for duplicate fix names across regions.
| Endpoint | Auth | Method | What It Returns |
|---|---|---|---|
/playbook/traversal |
No | POST | Waypoints, geometry, distance, ARTCCs, TRACONs, sectors for any route string |
/routes/cdrs |
No | GET | Pre-cataloged CDR routes with geometry |
/playbook/plays |
No | GET | FAA playbook routes with frozen geometry |
/flights |
API Key | GET | Active flight route strings, distances, SID/STAR, progress |
/positions |
API Key | GET | GeoJSON Point positions with optional route strings |
/tmi/routes |
No | GET | Active TMI reroute visualizations with geometry |
POST /api/swim/v1/playbook/traversal — No auth required
Submit up to 100 route strings and get back resolved waypoints, geometry, and facility traversals. This is the endpoint to use if you have your own route strings and want VATSWIM to process them.
{
"routes": [
"KJFK GREKI JUDDS CAM BUGSY POLTY J9 MLF ANJLL4 KLAX",
"KATL FRDMM4 BUURT HOBTT KARIT DCT SPS J86 TBC SUNSS5 KLAS"
],
"fields": ["artccs", "tracons", "sectors", "geometry", "distance", "waypoints"]
}| Parameter | Type | Description |
|---|---|---|
routes |
string[] | Route strings to process (max 100) |
fields |
string[] | Which outputs to include (omit for all) |
Valid fields values: artccs, tracons, sectors, geometry, distance, waypoints
{
"count": 2,
"results": [
{
"route_string": "KJFK GREKI JUDDS CAM BUGSY POLTY J9 MLF ANJLL4 KLAX",
"artccs": ["ZNY", "ZBW", "CZUL", "CZYZ", "ZMP", "ZLC", "ZLA"],
"tracons": ["N90", "L30"],
"sectors": {
"low": [],
"high": ["ZNY_66", "ZBW_38", "ZMP_21", "ZLC_15", "ZLA_37"],
"superhigh": []
},
"distance_nm": 2615.6,
"waypoints": [
{"seq": 1, "id": "KJFK", "lat": 40.6399281, "lon": -73.7786922, "type": "airport"},
{"seq": 2, "id": "GREKI", "lat": 41.4800083, "lon": -73.3141611, "type": "nav_fix"},
{"seq": 3, "id": "JUDDS", "lat": 41.6346722, "lon": -73.1082444, "type": "nav_fix"},
{"seq": 4, "id": "CAM", "lat": 42.9942888, "lon": -73.3440189, "type": "nav_fix"},
{"seq": 5, "id": "MLF", "lat": 38.3603556, "lon": -113.0132328, "type": "nav_fix"},
{"seq": 6, "id": "KLAX", "lat": 33.9425011, "lon": -118.4079971, "type": "airport"}
],
"geometry": {
"type": "LineString",
"coordinates": [
[-73.7786922, 40.6399281],
[-73.3141611, 41.4800083],
[-73.1082444, 41.6346722],
[-73.3440189, 42.9942888],
[-113.0132328, 38.3603556],
[-118.4079971, 33.9425011]
]
}
}
]
}import requests
resp = requests.post(
"https://perti.vatcscc.org/api/swim/v1/playbook/traversal",
json={
"routes": ["KJFK MERIT J584 RBV J230 WETRO DCT KMCO"],
"fields": ["geometry", "distance", "waypoints", "artccs"]
}
)
result = resp.json()["results"][0]
# Plot with any GeoJSON-compatible library
geojson = result["geometry"] # {"type": "LineString", "coordinates": [...]}
distance = result["distance_nm"] # 894.2
artccs = result["artccs"] # ["ZNY", "ZDC", "ZJX"]
waypoints = result["waypoints"] # [{seq, id, lat, lon, type}, ...]const resp = await fetch('https://perti.vatcscc.org/api/swim/v1/playbook/traversal', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
routes: ['KJFK GREKI JUDDS CAM J9 MLF ANJLL4 KLAX'],
fields: ['geometry', 'waypoints', 'distance']
})
});
const { results } = await resp.json();
// Add to MapLibre
map.addSource('route', {
type: 'geojson',
data: { type: 'Feature', geometry: results[0].geometry }
});
map.addLayer({
id: 'route-line', type: 'line', source: 'route',
paint: { 'line-color': '#0080ff', 'line-width': 2 }
});
// Add waypoint markers
results[0].waypoints.forEach(wp => {
new maplibregl.Marker().setLngLat([wp.lon, wp.lat]).addTo(map);
});GET /api/swim/v1/routes/cdrs — No auth required
Query the FAA's ~47K Coded Departure Routes catalog with optional geometry expansion.
| Param | Example | Description |
|---|---|---|
origin |
KJFK |
Filter by departure airport (ICAO) |
dest |
KLAX |
Filter by arrival airport (ICAO) |
code |
JFKLAX1D |
Exact CDR code lookup |
dep_artcc |
ZNY |
Filter by departure ARTCC |
arr_artcc |
ZLA |
Filter by arrival ARTCC |
include |
geometry |
Include resolved geometry + waypoints |
GET /api/swim/v1/routes/cdrs?origin=KJFK&dest=KLAX&include=geometry
{
"success": true,
"data": [
{
"cdr_code": "JFKLAX1D",
"full_route": "KJFK GREKI JUDDS CAM BUGSY POLTY UBTIX ULAMO STNRD COLDD EXHOS SWTHN DNW FFU J9 MLF WINEN Q73 HAKMN ANJLL4 KLAX",
"origin_icao": "KJFK",
"dest_icao": "KLAX",
"dep_artcc": "ZNY",
"arr_artcc": "ZLA",
"geometry": {
"type": "LineString",
"coordinates": [
[-73.7786922, 40.6399281], [-73.3141611, 41.4800083],
[-73.1082444, 41.6346722], [-73.3440189, 42.9942888],
[-74.1414111, 44.7226528], [-75.8110333, 45.899175],
[-77.8333333, 47.0], [-81.516667, 47.9],
[-87.05, 47.0166667], [-92.2966667, 46.7444444],
[-102.7087306, 46.6849528], [-105.2145278, 46.2328861],
[-110.3354744, 43.8282781], [-111.9405315, 40.2748946],
[-112.1191056, 39.9707833], [-113.0132328, 38.3603556],
[-113.5, 37.9333333], [-113.7118222, 37.0480278],
[-113.9009722, 36.6568694], [-114.0365417, 36.4110139],
[-114.2858778, 36.0854778], [-114.865275, 35.6648667],
[-115.0797333, 35.5078639], [-118.4079971, 33.9425011]
]
},
"distance_nm": 2615.6,
"artccs_traversed": ["ZNY", "ZBW", "CZUL", "CZYZ", "ZMP", "ZLC", "ZLA"]
},
{
"cdr_code": "JFKLAX1K",
"full_route": "KJFK GAYEL Q818 WOZEE KENPA CESNA ONL EKR HVE PROMT Q88 HAKMN ANJLL4 KLAX",
"distance_nm": 2297.2,
"artccs_traversed": ["ZNY", "ZOB", "CZYZ", "ZMP", "ZDV", "ZLC", "ZLA"]
}
]
}GET /api/swim/v1/playbook/plays — No auth required
FAA playbook routes with pre-computed ("frozen") geometry. ~56K routes organized into plays.
| Param | Description |
|---|---|
origin |
Origin airport ICAO filter |
dest |
Destination airport ICAO filter |
artcc |
Impacted ARTCC filter |
category |
Play category (e.g., CADENA PASA) |
include |
geometry — include route geometry |
format |
geojson — return as GeoJSON FeatureCollection |
Each playbook route can have a route_geometry envelope containing pre-resolved spatial data:
{
"geojson": {
"type": "LineString",
"coordinates": [[-73.778, 40.639], [-73.314, 41.480], ...]
},
"waypoints": [
{"fix": "KJFK", "lat": 40.6399, "lon": -73.7787},
{"fix": "GREKI", "lat": 41.4800, "lon": -73.3142},
{"fix": "CAM", "lat": 42.9943, "lon": -73.3440}
],
"distance_nm": 847.3
}GET /api/swim/v1/flights — Requires X-API-Key header
Returns active flight plans with route text, SID/STAR identification, distances, and progress. Does not include geometry or resolved waypoints (use the traversal endpoint for that).
Real example — BAW545 (London Heathrow → Hamburg, queried from production ADL):
{
"flight_plan": {
"route_text": "BPK Q295 SOMVA DCT MAVAS DCT VALAM DCT GASTU DCT OSTOR T904 RIBSO RIBSO3P",
"departure_aerodrome": "EGLL",
"arrival_aerodrome": "EDDH",
"alternate_aerodrome": null,
"departure_airspace": null,
"arrival_airspace": null,
"sid": null,
"star": "RIBSO3P",
"departure_point": null,
"arrival_point": "RIBSO"
},
"progress": {
"great_circle_distance": 367.0,
"total_flight_distance": 367.0,
"distance_to_destination": null,
"distance_flown": null,
"percent_complete": null
}
}To render routes for active flights, fetch route strings from /flights then batch-process them through /playbook/traversal:
import requests
API_KEY = "your_key"
headers = {"X-API-Key": API_KEY}
# 1. Get active flights
flights = requests.get(
"https://perti.vatcscc.org/api/swim/v1/flights?phase=en_route",
headers=headers
).json()["data"]
# 2. Extract route strings
route_strings = [f["flight_plan"]["route_text"] for f in flights if f["flight_plan"]["route_text"]]
# 3. Batch resolve geometry (100 routes per request)
for i in range(0, len(route_strings), 100):
batch = route_strings[i:i+100]
resolved = requests.post(
"https://perti.vatcscc.org/api/swim/v1/playbook/traversal",
json={"routes": batch, "fields": ["geometry", "distance"]}
).json()["results"]
for route in resolved:
# route["geometry"] -> GeoJSON LineString
# route["distance_nm"] -> total distance
passGET /api/swim/v1/positions — Requires X-API-Key header
Returns a GeoJSON FeatureCollection of aircraft positions as Point features. Add include_route=true to include the raw route string in each feature's properties.
{
"type": "FeatureCollection",
"features": [
{
"type": "Feature",
"geometry": {
"type": "Point",
"coordinates": [7.20709, 43.66047, 22]
},
"properties": {
"callsign": "EJU634N",
"aircraft": "A320",
"departure": "LFPO",
"destination": "LFMN",
"phase": "arrived",
"current_artcc": "LFMM-E",
"altitude": 22,
"groundspeed": 0,
"distance_remaining_nm": 0.4,
"gcd_nm": 364.6,
"pct_complete": 99.9,
"route_string": "LATRA DCT LAMUT DCT UTUVA DCT LERGA DCT LIQID DCT LATAM DCT TUNUR DCT NISAR"
}
}
]
}GET /api/swim/v1/tmi/routes — No auth required
Active Traffic Management Initiative route visualizations with stored GeoJSON geometry and styling.
| Param | Description |
|---|---|
filter |
active (default), all, future, past
|
format |
geojson — return as FeatureCollection |
facility |
Filter by ARTCC code |
Each route includes GeoJSON geometry and visualization styling. TMI routes are only present when a Traffic Management Initiative is actively publishing reroutes.
{
"route_string": "...",
"route_geojson": {"type": "LineString", "coordinates": [[lon, lat], ...]},
"origin_airports": ["KJFK", "KEWR"],
"dest_airports": ["KLAS"],
"facilities": ["ZNY", "ZOB", "ZDV", "ZLC", "ZLA"],
"color": "#FF6600",
"line_weight": 3,
"line_style": "solid",
"notes": "..."
}All endpoints support multiple output formats via the format query parameter:
| Format | Content-Type | Description |
|---|---|---|
json (default) |
application/json |
Standard JSON |
geojson |
application/geo+json |
GeoJSON FeatureCollection |
csv |
text/csv |
Comma-separated values |
kml |
application/vnd.google-earth.kml+xml |
Google Earth format |
xml |
application/xml |
XML |
ndjson |
application/x-ndjson |
Newline-delimited JSON (streaming) |
wss://perti.vatcscc.org/api/swim/v1/ws — Requires API key in connection params
Subscribe to real-time flight events. Position events include current coordinates but not route geometry. Use flight.created events to capture new route strings, then batch-resolve via the traversal endpoint.
const ws = new WebSocket('wss://perti.vatcscc.org/api/swim/v1/ws?key=YOUR_KEY');
ws.onopen = () => {
ws.send(JSON.stringify({
type: 'subscribe',
channels: ['flight.created', 'flight.position'],
filters: { artccs: ['ZNY', 'ZDC'] }
}));
};
ws.onmessage = (event) => {
const msg = JSON.parse(event.data);
if (msg.channel === 'flight.created') {
// msg.data.route contains the raw route string
// Queue it for traversal resolution
}
};| Tier | Rate Limit | Access |
|---|---|---|
| Public (no key) | 60 req/min | CDRs, Playbook, TMI Routes, Traversal |
| Developer | 120 req/min | + Flights, Positions, WebSocket |
| Partner | 300 req/min | All endpoints |
Request an API key at https://perti.vatcscc.org/swim-keys.php.
| You have... | You want... | Use this endpoint |
|---|---|---|
| A route string | Geometry + waypoints + distance | POST /playbook/traversal |
| An O/D pair | Pre-built CDR routes with geometry | GET /routes/cdrs?origin=X&dest=Y&include=geometry |
| Nothing specific | Browse FAA playbook routes | GET /playbook/plays?include=geometry |
| Active flights | Route strings to process |
GET /flights then POST /playbook/traversal
|
| Active flights | Current positions on a map | GET /positions |
| TMI situation | Reroute visualizations | GET /tmi/routes?format=geojson |
- Batch your traversal calls. Send up to 100 routes per POST instead of one at a time.
- Cache geometry. Route geometry rarely changes for the same route string. Cache by route string hash.
-
Use
fieldsselectively. If you only need geometry, don't request sectors. Each field adds PostGIS computation. - Prefer CDRs/Playbook for known routes. These have pre-computed ("frozen") geometry that returns instantly vs. live PostGIS expansion.
-
Use WebSocket for real-time. Don't poll
/flights— subscribe toflight.createdandflight.positionevents.
PERTI - Virtual Air Traffic Control System Command Center Production Site | GitHub | Report Issue
Last updated: 2026-02-25
Home Navigation Helper (NEW)
Comprehensive Guides
Getting Started
Architecture
Algorithms & Processing
- Algorithms Overview
- Algorithm ETA Calculation
- Algorithm Trajectory Tiering
- Algorithm Zone Detection
- Algorithm Route Parsing
- Algorithm Data Refresh
SWIM API (Public/External)
- SWIM API
- SWIM Routes API
- SWIM Playbook API
- SWIM Route Data Integration
- Building Route Processing
- CDM Connector Guide
PERTI API (Internal)
Features
Walkthroughs
Operations
Development
Analysis
- Analysis (index)
- ETA Accuracy (Jan-Mar 2026)
Reference