Flight briefing
Runnable examples for pre-flight and en-route briefings using the Flight Briefing endpoint. The API returns an IBM Granite-generated summary alongside structured weather and NOTAM sections.
| # | Question | Data used |
|---|---|---|
| 1 | Generate a full briefing for KJFK → KLAX and display the summary | Flight Briefing |
| 2 | Display NOTAM highlights from a briefing for EGLL → OMDB | Flight Briefing |
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. Full flight briefing summary
Question: Generate a JSON flight briefing for KJFK → KLAX and display the AI summary and weather conditions.
The response is structured JSON with summary, origin_briefing, and destination_briefing, or plain text with a briefing key — the script handles both. Briefing generation can take up to ~90 seconds; the script retries once on 503.
import os
import time
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_briefing(origin: str, destination: str) -> dict | None:
params = {
"origin": origin,
"destination": destination,
"include_weather": "true",
"include_notams": "true",
"format": "json",
}
for attempt in range(2):
try:
r = requests.get(
f"{BASE}/briefing/flight",
headers=HEADERS,
params=params,
timeout=(10, 100),
)
except requests.exceptions.Timeout:
if attempt == 0:
time.sleep(5)
continue
return None
if r.status_code == 404:
return None
if r.status_code in (502, 503, 504):
if attempt == 0:
time.sleep(8)
continue
return None
r.raise_for_status()
return r.json()
return None
def weather_snippet(airport_briefing: dict | None) -> str:
if not airport_briefing:
return "—"
wx = airport_briefing.get("weather") or {}
metar = wx.get("metar_raw")
if metar:
return metar[:72] + ("…" if len(metar) > 72 else "")
taf = wx.get("taf_raw")
if taf:
return f"TAF only: {taf[:60]}…"
return "No METAR/TAF in briefing"
def main() -> None:
data = fetch_briefing("KJFK", "KLAX")
if not data:
console.print("[yellow]No briefing returned.[/]")
return
if "briefing" in data and "summary" not in data:
console.print(Panel(data["briefing"], title="Flight Briefing (text)"))
return
summary = data.get("summary")
if summary:
console.print(Panel(summary, title="Briefing Summary (AI-generated — IBM Granite)"))
table = Table(title="Weather (METAR excerpt)")
table.add_column("Airport", style="cyan")
table.add_column("Observation")
origin = data.get("origin_briefing")
destination = data.get("destination_briefing")
table.add_row(f"Departure ({data.get('origin', 'KJFK')})", weather_snippet(origin))
table.add_row(f"Arrival ({data.get('destination', 'KLAX')})", weather_snippet(destination))
console.print(table)
restrictions = data.get("critical_restrictions") or []
if restrictions:
console.print(Panel("\n".join(f"• {x}" for x in restrictions), title="Critical restrictions"))
console.print(
"\n[dim]Briefing summary is AI-generated. Always verify critical weather "
"conditions directly against METAR and TAF before flight.[/dim]"
)
if __name__ == "__main__":
main()Output: An AI-generated summary panel, a METAR excerpt table for departure and arrival, and optional critical-restriction bullets. Falls back to plain text when the API returns a briefing string instead of structured JSON.
2. NOTAM highlights from a briefing
Question: What are the active NOTAMs at departure and arrival for the EGLL → OMDB route?
import os
import time
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_briefing(origin: str, destination: str) -> dict | None:
params = {
"origin": origin,
"destination": destination,
"include_weather": "false",
"include_notams": "true",
"format": "json",
}
for attempt in range(2):
try:
r = requests.get(
f"{BASE}/briefing/flight",
headers=HEADERS,
params=params,
timeout=(10, 100),
)
except requests.exceptions.Timeout:
if attempt == 0:
time.sleep(5)
continue
return None
if r.status_code == 404:
return None
if r.status_code in (502, 503, 504):
if attempt == 0:
time.sleep(8)
continue
return None
r.raise_for_status()
return r.json()
return None
def print_notam_table(label: str, notams: list[dict]) -> None:
top = notams[:3]
table = Table(title=f"NOTAMs — {label} (top {len(top)})")
table.add_column("NOTAM ID", style="cyan", min_width=12)
table.add_column("Body (truncated)")
for notam in top:
notam_id = notam.get("notam_id") or notam.get("id") or "—"
body = notam.get("body") or notam.get("raw") or "—"
body_short = body[:80] + ("…" if len(body) > 80 else "")
table.add_row(str(notam_id), body_short)
console.print(table)
def main() -> None:
data = fetch_briefing("EGLL", "OMDB")
if not data:
console.print("[yellow]No briefing returned.[/]")
return
if "briefing" in data and "origin_briefing" not in data:
console.print(Panel(data["briefing"], title="Flight Briefing (text — no structured NOTAMs)"))
return
origin = data.get("origin_briefing") or {}
destination = data.get("destination_briefing") or {}
dep_notams = origin.get("notams") or []
arr_notams = destination.get("notams") or []
if not dep_notams and not arr_notams:
console.print("[yellow]No NOTAMs embedded in briefing response.[/]")
summary = data.get("summary") or data.get("briefing")
if summary:
console.print(Panel(str(summary), title="Briefing summary"))
return
if dep_notams:
print_notam_table(f"Departure (EGLL) — {len(dep_notams)} total", dep_notams)
else:
console.print("[dim]No departure NOTAMs in briefing.[/]")
if arr_notams:
print_notam_table(f"Arrival (OMDB) — {len(arr_notams)} total", arr_notams)
else:
console.print("[dim]No arrival NOTAMs in briefing.[/]")
if __name__ == "__main__":
main()Output: Up to three NOTAMs per airport from origin_briefing.notams and destination_briefing.notams. Falls back to the plain-text briefing field when structured JSON is unavailable.