FAA delays
Runnable examples for querying FAA ground delay programs, ground stops, closures, and airspace flow programs. See the FAA Delays reference for field definitions. Data covers US airports only (FAA ATCSCC programs).
| # | Question | Data used |
|---|---|---|
| 1 | Are there any active FAA delays across the US right now? | GET /delays/faa |
| 2 | Is KJFK currently under a ground delay program? | GET /delays/faa/{icao} |
| 3 | Scan hub airports for any active programs | GET /delays/faa/{icao} |
Requirements
x-api-key on every request (direct subscription). Learn more →Install
The scripts below use requests for API calls and rich for terminal output. Install once:
pip install requests rich1. Nationwide FAA delay snapshot
Question: Are there any active FAA delays across the US right now?
A single call to /delays/faa returns all current ground delay programs, ground stops, closures, and airspace flow programs. Cache for no more than 2 minutes.
import os
import requests
from rich.console import Console
from rich.panel import Panel
from rich.table import Table
console = Console()
HEADERS = {
"X-RapidAPI-Key": os.getenv("RAPIDAPI_KEY", "YOUR_RAPIDAPI_KEY"),
"X-RapidAPI-Host": "skylink-api.p.rapidapi.com",
}
BASE = "https://skylink-api.p.rapidapi.com"
def fetch_faa_delays() -> dict | None:
r = requests.get(f"{BASE}/delays/faa", headers=HEADERS, timeout=(10, 15))
if r.status_code == 404:
return None
r.raise_for_status()
return r.json()
def main() -> None:
data = fetch_faa_delays()
if not data:
console.print("[red]Could not retrieve FAA delay data.[/red]")
return
total = data.get("total_alerts", 0)
if total == 0:
console.print("[green]No active FAA delays.[/green]")
return
console.print(Panel(f"[bold]{total}[/bold] active FAA alert(s)", style="yellow"))
ground_delays = data.get("ground_delays", [])
if ground_delays:
t = Table(title="Ground Delay Programs (GDP)", show_lines=True)
t.add_column("Airport", style="yellow")
t.add_column("Name")
t.add_column("Avg Delay")
t.add_column("Max Delay")
t.add_column("Reason")
for row in ground_delays:
t.add_row(
row.get("airport", "—"),
row.get("airport_name", "—"),
row.get("avg_delay", "—"),
row.get("max_delay", "—"),
row.get("reason", "—"),
)
console.print(t)
ground_stops = data.get("ground_stops", [])
if ground_stops:
t = Table(title="Ground Stops (GS)", show_lines=True)
t.add_column("Airport", style="red")
t.add_column("Name")
t.add_column("End Time")
t.add_column("Reason")
for row in ground_stops:
t.add_row(
row.get("airport", "—"),
row.get("airport_name", "—"),
row.get("end_time", "—"),
row.get("reason", "—"),
)
console.print(t)
closures = data.get("closures", [])
if closures:
t = Table(title="Closures", show_lines=True)
t.add_column("Airport", style="magenta")
t.add_column("Name")
t.add_column("Begin")
t.add_column("Reopen")
t.add_column("Reason")
for row in closures:
t.add_row(
row.get("airport", "—"),
row.get("airport_name", "—"),
row.get("begin", "—"),
row.get("reopen", "—"),
row.get("reason", "—"),
)
console.print(t)
if __name__ == "__main__":
main()Output: Prints "No active FAA delays" when the system is clear. Otherwise shows a summary panel followed by colour-coded tables for each alert type — yellow for GDPs, red for ground stops, magenta for closures.
2. KJFK delay status
Question: Is KJFK currently under a ground delay program?
Use the airport-specific endpoint to check a single airport without downloading the full nationwide picture.
import os
import requests
from rich.console import Console
from rich.panel import Panel
console = Console()
HEADERS = {
"X-RapidAPI-Key": os.getenv("RAPIDAPI_KEY", "YOUR_RAPIDAPI_KEY"),
"X-RapidAPI-Host": "skylink-api.p.rapidapi.com",
}
BASE = "https://skylink-api.p.rapidapi.com"
AIRPORT = "KJFK"
def fetch_airport_delays(icao: str) -> dict | None:
r = requests.get(
f"{BASE}/delays/faa/{icao}",
headers=HEADERS,
timeout=(10, 15),
)
if r.status_code == 404:
return None
r.raise_for_status()
return r.json()
def main() -> None:
data = fetch_airport_delays(AIRPORT)
if not data:
console.print(f"[red]No delay data returned for {AIRPORT}.[/red]")
return
total = data.get("total_alerts", 0)
if total == 0:
console.print(
Panel(f"[green]No active delays at {AIRPORT}.[/green]", style="green")
)
return
for gd in data.get("ground_delays", []):
console.print(
Panel(
f"[bold yellow]Ground Delay Program (GDP)[/bold yellow]\n"
f"Avg delay: {gd.get('avg_delay', '—')} "
f"Max delay: {gd.get('max_delay', '—')}\n"
f"Reason: {gd.get('reason', '—')}",
style="yellow",
title=AIRPORT,
)
)
for gs in data.get("ground_stops", []):
console.print(
Panel(
f"[bold red]Ground Stop (GS)[/bold red]\n"
f"End time: {gs.get('end_time', '—')}\n"
f"Reason: {gs.get('reason', '—')}",
style="red",
title=AIRPORT,
)
)
for cl in data.get("closures", []):
console.print(
Panel(
f"[bold magenta]Closure[/bold magenta]\n"
f"Begin: {cl.get('begin', '—')} Reopen: {cl.get('reopen', '—')}\n"
f"Reason: {cl.get('reason', '—')}",
style="magenta",
title=AIRPORT,
)
)
if __name__ == "__main__":
main()Output: A green "No active delays" panel when clear. Otherwise, a colour-coded panel per alert type (yellow GDP, red ground stop, magenta closure) with timing and reason details.
3. Hub airport delay dashboard
Question: Which of my hub airports have active FAA programs right now?
Fetch each hub individually and build a single dashboard table. Refresh no more often than every 2 minutes.
import os
import concurrent.futures
import requests
from rich.console import Console
from rich.table import Table
console = Console()
HEADERS = {
"X-RapidAPI-Key": os.getenv("RAPIDAPI_KEY", "YOUR_RAPIDAPI_KEY"),
"X-RapidAPI-Host": "skylink-api.p.rapidapi.com",
}
BASE = "https://skylink-api.p.rapidapi.com"
HUB_AIRPORTS = ["KJFK", "KLAX", "KORD", "KATL"]
def fetch_airport_delays(icao: str) -> tuple[str, dict | None]:
try:
r = requests.get(
f"{BASE}/delays/faa/{icao}",
headers=HEADERS,
timeout=(10, 15),
)
if r.status_code == 404:
return icao, None
r.raise_for_status()
return icao, r.json()
except Exception as exc: # noqa: BLE001
console.print(f"[red]Error fetching {icao}: {exc}[/red]")
return icao, None
def summarise(data: dict | None) -> tuple[str, str, str, str]:
"""Return (active, alert_type, avg_delay, reason_snippet)."""
if not data or data.get("total_alerts", 0) == 0:
return "NO", "—", "—", "—"
types = []
avg_delay = "—"
reason = "—"
for gd in data.get("ground_delays", []):
types.append("GDP")
avg_delay = gd.get("avg_delay", "—")
reason = (gd.get("reason") or "")[:40]
for _ in data.get("ground_stops", []):
types.append("GS")
for _ in data.get("closures", []):
types.append("Closure")
for _ in data.get("airspace_flow_programs", []):
types.append("AFP")
return "YES", ", ".join(types) or "—", avg_delay, reason or "—"
def main() -> None:
with concurrent.futures.ThreadPoolExecutor(max_workers=4) as pool:
results = dict(pool.map(fetch_airport_delays, HUB_AIRPORTS))
table = Table(title="Hub Airport FAA Delay Dashboard", show_lines=True)
table.add_column("Airport", style="bold", no_wrap=True)
table.add_column("Active", justify="center")
table.add_column("Alert Type")
table.add_column("Avg Delay", justify="center")
table.add_column("Reason")
for icao in HUB_AIRPORTS:
active, alert_type, avg_delay, reason = summarise(results.get(icao))
color = "red" if active == "YES" else "green"
table.add_row(
icao,
f"[{color}]{active}[/{color}]",
alert_type,
avg_delay,
reason,
)
console.print(table)
console.print("[dim]Cache for 2 minutes max — FAA ATCSCC data, US only.[/dim]")
if __name__ == "__main__":
main()Output: A single dashboard table with one row per hub. Airports with active programs show in red; clear airports in green. Alert type, average delay, and reason snippet are included per row.