NOTAMs
Runnable examples for working with NOTAMs: active notice summaries, aerodrome filtering, and pre-flight multi-airport checks. See the NOTAMs reference for field definitions.
| # | Question | Data used |
|---|---|---|
| 1 | Fetch all active NOTAMs for KJFK and display a summary | GET /notams/{icao} |
| 2 | Filter runway-related NOTAMs (aerodrome scope) at EGLL | GET /notams/{icao} |
| 3 | Pre-flight NOTAM check: departure and arrival airports | GET /notams/{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. Active NOTAM summary for KJFK
Question: What NOTAMs are currently active at KJFK?
NOTAMs update frequently — cache for no more than 5 minutes. This script fetches all active notices and displays a sortable summary table.
import os
from datetime import datetime
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"
def fetch_notams(icao: str) -> dict | None:
r = requests.get(
f"{BASE}/notams/{icao}",
headers=HEADERS,
timeout=(10, 15),
)
if r.status_code == 404:
return None
r.raise_for_status()
return r.json()
def format_dt(val: str | None) -> str:
if not val:
return "—"
try:
return datetime.fromisoformat(val).strftime("%m/%d %H:%Mz")
except ValueError:
return val[:16]
def main() -> None:
data = fetch_notams("KJFK")
if not data:
console.print("[red]No NOTAM data returned for KJFK.[/red]")
return
notams = data.get("notams", [])
total = data.get("total", len(notams))
sorted_notams = sorted(
notams,
key=lambda n: n.get("effective") or "",
)
table = Table(
title=f"KJFK NOTAMs — {total} active",
show_lines=True,
)
table.add_column("NOTAM ID", style="cyan", no_wrap=True)
table.add_column("Type", justify="center")
table.add_column("Scope", justify="center")
table.add_column("Effective", no_wrap=True)
table.add_column("Expiration", no_wrap=True)
table.add_column("Body")
for n in sorted_notams:
body = n.get("body") or n.get("raw", "")
snippet = (body[:60] + "…") if len(body) > 60 else body
table.add_row(
n.get("notam_id") or n.get("notam_id_domestic") or "—",
n.get("type") or "—",
n.get("scope") or "—",
format_dt(n.get("effective")),
format_dt(n.get("expiration")),
snippet,
)
console.print(table)
if __name__ == "__main__":
main()Output: A table of all active NOTAMs sorted by effective time, showing ID, type, scope, validity window, and a 60-character body preview.
2. Aerodrome NOTAMs at EGLL
Question: Which NOTAMs at EGLL are aerodrome-scoped (runway/taxiway closures, lighting outages)?
Aerodrome NOTAMs (scope == "AERODROME") directly affect ground operations. Filter to these before taxi briefings. You can also drop scope: "FIR" entries server-side with ?exclude_scope=FIR instead of filtering client-side.
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_notams(icao: str) -> dict | None:
r = requests.get(
f"{BASE}/notams/{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_notams("EGLL")
if not data:
console.print("[red]No NOTAM data returned for EGLL.[/red]")
return
all_notams = data.get("notams", [])
aerodrome = [n for n in all_notams if n.get("scope") == "AERODROME"]
if not aerodrome:
console.print("[yellow]No aerodrome NOTAMs active at EGLL.[/yellow]")
return
console.print(
Panel(
f"[bold]{len(aerodrome)}[/bold] aerodrome-scoped NOTAM(s) at EGLL "
f"(scope=AERODROME: runway/taxiway closures, lighting outages)",
style="yellow",
)
)
table = Table(show_lines=True)
table.add_column("NOTAM ID", style="cyan", no_wrap=True)
table.add_column("Type", justify="center")
table.add_column("Q-Code")
table.add_column("Body")
for n in aerodrome:
body = n.get("body") or n.get("raw", "")
snippet = (body[:80] + "…") if len(body) > 80 else body
table.add_row(
n.get("notam_id") or n.get("notam_id_domestic") or "—",
n.get("type") or "—",
n.get("q_code") or "—",
snippet,
)
console.print(table)
if __name__ == "__main__":
main()Output: A panel showing the aerodrome NOTAM count followed by a table with ID, type, Q-code, and truncated body. Prints "No aerodrome NOTAMs active" if none match.
3. Pre-flight NOTAM check: departure and arrival
Question: What NOTAMs are active at both my departure (KJFK) and arrival (KLAX) airports?
Fetch both airports concurrently to minimize latency. Review all NOTAMs — do not rely on automated parsing alone.
import os
import concurrent.futures
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"
DEPARTURE = "KJFK"
ARRIVAL = "KLAX"
def fetch_notams(icao: str) -> tuple[str, dict | None]:
try:
r = requests.get(
f"{BASE}/notams/{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 print_airport_notams(icao: str, data: dict | None) -> None:
if not data:
console.print(Panel(f"[red]No data for {icao}[/red]"))
return
notams = data.get("notams", [])
total = data.get("total", len(notams))
console.print(
Panel(
f"[bold cyan]{icao}[/bold cyan] — {total} active NOTAM(s)",
style="blue",
)
)
for n in notams[:5]:
body = n.get("body") or n.get("raw", "")
notam_id = n.get("notam_id") or n.get("notam_id_domestic") or "—"
scope = n.get("scope") or "—"
snippet = (body[:80] + "…") if len(body) > 80 else body
console.print(f" [cyan]{notam_id}[/cyan] [{scope}] {snippet}")
if total > 5:
console.print(f" [dim]… and {total - 5} more NOTAM(s)[/dim]")
console.print()
def main() -> None:
airports = [DEPARTURE, ARRIVAL]
with concurrent.futures.ThreadPoolExecutor(max_workers=2) as pool:
results = dict(pool.map(lambda a: fetch_notams(a), airports))
for icao in airports:
print_airport_notams(icao, results.get(icao))
console.print(
"[bold yellow]⚠ Review all NOTAMs — do not rely on automated "
"parsing alone.[/bold yellow]"
)
if __name__ == "__main__":
main()Output: Two sections — one per airport — each showing the total NOTAM count and the first 5 notices as a compact list. A reminder to review all NOTAMs manually is printed at the end.