PIREPs (Pilot Reports)
PIREPs (Pilot Reports) are voluntary in-flight weather observations filed by pilots that capture conditions automated sensors miss — turbulence, icing, cloud tops, visibility, and temperature aloft — often minutes before they appear in forecasts. This endpoint returns every PIREP whose position falls inside your bounding box within a configurable time window. Use PIREPs alongside METAR, TAF, and AIRMET/SIGMET when you need recent pilot-observed hazards along a route. Reports are geographic — pass a bounding box around your flight path, not a single airport ICAO. Coverage is US-focused; queries over areas with low pilot traffic often return empty reports arrays even when the bbox is valid.
Report types: UA (routine PIREP) and UUA (urgent PIREP — significant hazard; prioritize in your UI).
Request
Requirements
x-api-key on every request (direct subscription). Learn more →Send a GET with a geographic bounding box and optional look-back window.
https://data.skylinkapi.com/v3/weather/pireps| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
bbox | string | Yes | - | Bounding box as lat1,lon1,lat2,lon2 — southwest corner first. Example: 39,-78,42,-71 (Northeast US corridor) |
hours | integer | No | 2 | How far back to search, in hours (1–24) |
Bounding box tips. Size the box to your route segment plus a buffer — PIREPs are sparse outside busy airspace. An empty reports array is a normal response when no pilots filed reports in the area recently.
Response
{
"bbox": "39.0,-78.0,42.0,-71.0",
"hours": 3,
"reports": [
{
"raw": "UA /OV JFK/TM 1845/FL085/TP B738/TB MOD/RM CONT MOD CHOP",
"report_type": "UA",
"location": "JFK",
"time": "2025-01-15T18:45:00Z",
"altitude": "FL085",
"aircraft_type": "B738",
"turbulence": "Moderate",
"icing": null,
"sky_conditions": null,
"temperature": null,
"wind": null,
"remarks": "CONT MOD CHOP",
"latitude": 40.64,
"longitude": -73.78
}
],
"total": 1
}When no reports match, the API returns "reports": [] and "total": 0 — not an error.
| Field | Type | Required | Description |
|---|---|---|---|
bbox | string | Yes | Echo of the queried bounding box |
hours | integer | Yes | Look-back window applied |
reports | array | Yes | Matching PIREPs (may be empty) |
total | integer | Yes | Count of items in reports |
Report
JSON path: reports[]. Only raw is guaranteed non-null. All decoded fields are null when not present in the filed report — expect sparse objects, especially on older or brief PIREPs.
| Field | Type | Required | Null? | Description |
|---|---|---|---|---|
raw | string | Yes | Never | Full PIREP text as filed |
report_type | string | null | Yes (key always present) | Yes | UA (routine) or UUA (urgent) |
location | string | null | Yes (key always present) | Yes | Location identifier or bearing/distance from a navaid |
time | string | null | Yes (key always present) | Yes | Observation time (UTC, ISO 8601) |
altitude | string | null | Yes (key always present) | Yes | Flight level or altitude, e.g. FL085 |
aircraft_type | string | null | Yes (key always present) | Yes | Aircraft type code, e.g. B738 |
sky_conditions | string | null | Yes (key always present) | Yes | Sky or cloud conditions |
turbulence | string | null | Yes (key always present) | Yes | Turbulence intensity — see Intensity scales |
icing | string | null | Yes (key always present) | Yes | Icing intensity — see Intensity scales |
temperature | string | null | Yes (key always present) | Yes | Outside air temperature |
wind | string | null | Yes (key always present) | Yes | Wind direction and speed |
remarks | string | null | Yes (key always present) | Yes | Additional remarks |
latitude | number | null | Yes (key always present) | Yes | Report latitude when geocoded |
longitude | number | null | Yes (key always present) | Yes | Report longitude when geocoded |
Object schemas and nullability
Every key in a Report object is always present — nothing is omitted when a field is not reported. Use null when the pilot did not include a section.
| Situation | What you get | Not this |
|---|---|---|
| Pilot omitted turbulence | turbulence: null | key missing |
| Pilot omitted icing | icing: null | key missing |
| Navaid-relative position only | latitude: null, longitude: null | key missing |
| No reports in window | reports: [], total: 0 | null, HTTP error |
| Routine report | report_type: "UA" | null |
| Urgent hazard report | report_type: "UUA" | "UA" |
Intensity scales
Decoded turbulence and icing strings follow standard PIREP intensity vocabulary. Values are decoded text; the exact string may vary slightly between reports.
| Turbulence (examples) | Meaning |
|---|---|
NEG / Negative | None reported |
LGT / Light | Light |
MOD / Moderate | Moderate |
SVR / Severe | Severe |
EXTM / Extreme | Extreme |
| Icing (examples) | Meaning |
|---|---|
NEG / Negative | None |
TRC / Trace | Trace |
LGT / Light | Light |
MOD / Moderate | Moderate |
SVR / Severe | Severe |
Client types
"""PIREP response types - matches pireps field tables."""from dataclasses import dataclass@dataclassclass PirepReport: raw: str report_type: str | None = None location: str | None = None time: str | None = None altitude: str | None = None aircraft_type: str | None = None sky_conditions: str | None = None turbulence: str | None = None icing: str | None = None temperature: str | None = None wind: str | None = None remarks: str | None = None latitude: float | None = None longitude: float | None = None@dataclassclass PirepResponse: bbox: str hours: int reports: list[PirepReport] total: intIntegration
Poll PIREPs along a route bounding box and surface urgent reports first.
The example queries a corridor bbox, caches results for 10 minutes (PIREPs are ephemeral), and returns only UUA urgent reports plus the highest turbulence severity seen. An empty reports array is normal on quiet routes — render "no recent pilot reports," never an error state. Prioritize UUA reports above routine UA in dispatch or EFB UIs.
import osimport timefrom typing import TypedDictimport requestsHEADERS = { "x-api-key": os.getenv("SKYLINK_API_KEY", "YOUR_API_KEY")}BASE = "https://data.skylinkapi.com/v3"CACHE: dict[str, tuple[dict, float]] = {}PIREP_TTL = 600 # 10 min - PIREPs are short-livedclass PirepReport(TypedDict, total=False): raw: str report_type: str | None turbulence: str | None icing: str | None time: str | Nonedef fetch_pireps(bbox: str, hours: int = 3) -> dict: cache_key = f"pirep:{bbox}:{hours}" cached = CACHE.get(cache_key) if cached and time.time() < cached[1]: return cached[0] r = requests.get( f"{BASE}/weather/pireps", headers=HEADERS, params={"bbox": bbox, "hours": hours}, timeout=(10, 20), ) r.raise_for_status() data = r.json() CACHE[cache_key] = (data, time.time() + PIREP_TTL) return datadef urgent_reports(bbox: str, hours: int = 3) -> list[PirepReport]: payload = fetch_pireps(bbox, hours=hours) reports: list[PirepReport] = payload.get("reports", []) return [r for r in reports if r.get("report_type") == "UUA"]if __name__ == "__main__": import json bbox = "-74.5,40.3,-73.5,41.0" payload = fetch_pireps(bbox, hours=3) print(json.dumps(payload, indent=2, default=str)[:3000])Implementation notes
Sparse data is normal. Unlike METAR, PIREPs depend on pilots filing reports. Widen the bbox or increase hours before assuming the API is broken.
Prioritize UUA. Urgent PIREPs indicate significant hazards. Treat any UUA with turbulence: "SVR" or "EXTM" as an immediate alert.
Geocoding gaps. latitude and longitude are null when the report uses navaid-relative position only (e.g. 25 SW of ORL). Fall back to parsing location and raw for display; do not drop these reports.
Do not over-poll. A 5–15 minute refresh interval is sufficient. Combine with AIRMET/SIGMET for area-wide advisories.
time vs request time. time is the observation time from the PIREP — use it for "X minutes ago" display. There is no separate API fetch timestamp on PIREPs.
Error responses
Endpoint-specific failures only. For auth, validation, rate limits, and server errors, see Error Handling.
400 — invalid bbox format
{
"detail": "Invalid bounding box format. Expected 'lat1,lon1,lat2,lon2'"
}503 — upstream unavailable
{
"detail": "PIREP service temporarily unavailable"
}Retry with exponential backoff. A single retry after 5–10 seconds is usually sufficient.
Your SkyLink licence key, for keys bought direct from skylinkapi.com.
In: header
Query Parameters
Bounding box as 'lat1,lon1,lat2,lon2' (SW corner → NE corner)
Time window in hours (how far back to look)
21 <= value <= 24Response Body
application/json
application/json
curl -X GET "https://data.skylinkapi.com/v3/weather/pireps?bbox=string"{
"bbox": "39,-78,42,-71",
"hours": 2,
"reports": [
{
"raw": "UA /OV JFK/TM 1845/FL085/TP B738/TB MOD/RM CONT MOD CHOP",
"report_type": "UA",
"location": "JFK",
"time": "2025-01-15T18:45:00Z",
"altitude": "FL085",
"aircraft_type": "B738",
"turbulence": "Moderate",
"remarks": "CONT MOD CHOP"
}
],
"total": 1
}{
"detail": [
{
"loc": [
"string"
],
"msg": "string",
"type": "string",
"input": null,
"ctx": {}
}
]
}Related: Weather hub · AIRMET/SIGMET · METAR · Urgent PIREP use case