Single Flight Detail
Get full metadata and the complete position track for a specific archived flight. Both endpoints require a flight_id UUID from flight history search — they are step 2 in the same workflow. Plan tiers: Historical ADS-B hub.
Requirements
x-api-key on every request (direct subscription). Learn more →Pro, Ultra, or Mega — use the path prefix that matches the window you need.
Learn more →Single flight detail
Returns enriched metadata beyond search results — off-block/on-block times, arrival proximity, and audit timestamps. Block time is gate-to-gate time including taxi; off-block = gate departure, on-block = gate arrival. Takeoff and landing are wheels-up/wheels-down events, distinct from off-block/on-block.
Request
https://data.skylinkapi.com/v3.1/ultra/history/flight/{flight_id}| Parameter | Type | Required | Description |
|---|---|---|---|
flight_id | string | Yes | Flight UUID from flight history search |
MEGA path (`/mega/history/...`)Expand section
https://data.skylinkapi.com/v3.1/mega/history/flight/{flight_id}Same parameters and response shape as ULTRA. Requires Ultra or Mega plan. flight_id values are interchangeable across tiers.
Response
{
"flight_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"icao24": "40621d",
"callsign": "BAW178",
"flight_number": "BAW178",
"tail_number": "G-XWBA",
"aircraft_type_icao": "B77W",
"aircraft_type_name": "Boeing 777-300ER",
"airline_icao": "BAW",
"airline_iata": "BA",
"airline_name": "British Airways",
"departure_airport_icao": "EGLL",
"departure_airport_iata": "LHR",
"departure_airport_name": "London Heathrow Airport",
"arrival_airport_icao": "KJFK",
"arrival_airport_iata": "JFK",
"arrival_airport_name": "John F Kennedy International Airport",
"flight_state": "ARCHIVED",
"flight_start": "2026-05-12T19:42:05Z",
"flight_end": "2026-05-13T03:11:10Z",
"takeoff_time": "2026-05-12T19:45:00Z",
"landing_time": "2026-05-13T03:08:00Z",
"off_block_time": null,
"on_block_time": null,
"flight_duration_min": 443.0,
"duration_source": "estimated",
"distance_nm": 2998.4,
"arrival_distance_nm": 2.1,
"confidence": 1.0,
"route_source": "vrs_confirmed",
"gps_spoofing_suspected": false,
"diversion_suspected": false,
"created_at": "2026-05-12T19:40:00Z",
"updated_at": "2026-05-13T03:15:00Z"
}Returns the same core fields as a flight summary plus detail-only enrichment when available.
| Field | Type | Required | Null? | Description |
|---|---|---|---|---|
| (all flight summary fields) | - | - | - | Same shape as search results |
off_block_time | string | null | No | Yes | Off-block time when known (ISO 8601) |
on_block_time | string | null | No | Yes | On-block time when known (ISO 8601) |
duration_source | string | null | No | Yes | How duration was computed — when "estimated", block time was inferred from position data rather than recorded gate events (important for ESG or delay-reporting workflows) |
arrival_distance_nm | number | null | No | Yes | Distance from last position to arrival airport (nm) |
created_at | string | null | No | Yes | When the archive record was created (ISO 8601) |
updated_at | string | null | No | Yes | When the archive record was last updated (ISO 8601) |
Client types
"""Typed models for Historical ADS-B - matches historical-adsb.mdx field tables."""from __future__ import annotationsfrom dataclasses import dataclassfrom typing import Literal@dataclassclass HistoricalFlightSummary: flight_id: str icao24: str | None callsign: str | None flight_number: str | None tail_number: str | None departure_airport_icao: str | None arrival_airport_icao: str | None flight_start: str flight_end: str takeoff_time: str | None landing_time: str | None flight_duration_min: float | None distance_nm: float | None@dataclassclass HistoricalPosition: timestamp: str icao24: str latitude: float longitude: float altitude_baro: float | None ground_speed: float | None track: float | None vertical_rate: float | None is_on_ground: bool@dataclassclass HistoricalFlightWindow: flight_id: str callsign: str | None departure_airport_icao: str | None arrival_airport_icao: str | None takeoff_time: str | None landing_time: str | None flight_start: str flight_end: str flight_state: str | None@dataclassclass AirportTrafficFlight: flight_id: str icao24: str | None callsign: str | None departure_airport_icao: str | None arrival_airport_icao: str | None takeoff_time: str | None landing_time: str | None flight_duration_min: float | None distance_nm: float | None@dataclassclass AirportTrafficResponse: icao: str direction: Literal["dep", "arr", "both"] count: int flights: list[AirportTrafficFlight]Integration
Fetch enriched metadata for a single archived flight — off-block/on-block times, arrival proximity, and audit timestamps. The example below chains from a flight search result: it takes the first flight_id and fetches full detail, then maps gate times into a display object with a fallback when block times are null.
import osimport requestsBASE = "https://data.skylinkapi.com/v3.1"HEADERS = { "x-api-key": os.getenv("SKYLINK_API_KEY") or os.getenv("SKYLINK_API_KEY", "YOUR_API_KEY")}def fetch_flight_detail(flight_id: str, *, tier: str = "ultra") -> dict: r = requests.get( f"{BASE}/{tier}/history/flight/{flight_id}", headers=HEADERS, timeout=(10, 25), ) r.raise_for_status() return r.json()def search_one_flight(*, callsign: str = "BAW178", tier: str = "ultra") -> dict | None: r = requests.get( f"{BASE}/{tier}/history/flights", headers=HEADERS, params={"callsign": callsign, "limit": 1}, timeout=(10, 25), ) r.raise_for_status() flights = r.json().get("flights") or [] return flights[0] if flights else Noneif __name__ == "__main__": import json hit = search_one_flight() if not hit: print("No flight found") else: detail = fetch_flight_detail(hit["flight_id"]) print(json.dumps({"callsign": detail.get("callsign"), "flight_id": detail.get("flight_id"), "route": [detail.get("departure_airport_icao"), detail.get("arrival_airport_icao")]}, indent=2))Implementation notes
Chain from search. Always obtain flight_id from Flight History Search first — guessing UUIDs returns 404. Detail and search use the same tier path (/ultra/... or /mega/...).
Block times vs takeoff/landing. off_block_time and on_block_time are gate events; takeoff_time and landing_time are wheels-up/wheels-down. Both may be null when ADS-B coverage was incomplete near the gate.
Raw position history. For a time-bounded timeline without flight segmentation, see Position History.
Error responses
Plan-gate 401/403: Historical ADS-B hub. Endpoint-specific:
404 — flight not found
{
"detail": "Flight not found"
}Returned when flight_id is not in the archive (unknown UUID, outside retention, or typo). Search again with a narrower window — see Flight History Search.
Your SkyLink licence key, for keys bought direct from skylinkapi.com.
In: header
Path Parameters
Response Body
application/json
application/json
curl -X GET "https://data.skylinkapi.com/v3.1/ultra/history/flight/00000000-0000-0000-0000-000000000001"null{
"detail": [
{
"loc": [
"string"
],
"msg": "string",
"type": "string",
"input": null,
"ctx": {}
}
]
}Your SkyLink licence key, for keys bought direct from skylinkapi.com.
In: header
Path Parameters
Response Body
application/json
application/json
curl -X GET "https://data.skylinkapi.com/v3.1/mega/history/flight/00000000-0000-0000-0000-000000000001"null{
"detail": [
{
"loc": [
"string"
],
"msg": "string",
"type": "string",
"input": null,
"ctx": {}
}
]
}Flight track
Returns the full ADS-B position track for a specific flight, automatically bounded to its takeoff → landing window (5-minute pad on each side). Use this when you have a flight_id from search and want the path without computing the time window yourself.
Request
https://data.skylinkapi.com/v3.1/ultra/history/flight/{flight_id}/track| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
flight_id | string | Yes | - | Flight UUID from search |
limit | integer | No | 2000 | Max position rows (max 5,000 on ULTRA path) |
MEGA path (`/mega/history/...`)Expand section
https://data.skylinkapi.com/v3.1/mega/history/flight/{flight_id}/track| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
flight_id | string | Yes | - | Flight UUID |
limit | integer | No | 5000 | Max positions (max 10,000 on MEGA path) |
Requires Ultra or Mega plan. Same response shape as ULTRA.
Response
{
"flight_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"icao24": "40621d",
"callsign": "BAW178",
"registration": "G-XWBA",
"aircraft_type_icao": "B77W",
"departure_airport_icao": "EGLL",
"departure_airport_iata": "LHR",
"arrival_airport_icao": "KJFK",
"arrival_airport_iata": "JFK",
"takeoff_time": "2026-05-12T19:45:00Z",
"landing_time": "2026-05-13T03:08:00Z",
"count": 1287,
"positions": [
{
"timestamp": "2026-05-13T03:08:05Z",
"icao24": "40621d",
"latitude": 40.6413,
"longitude": -73.7781,
"altitude_baro": 0,
"ground_speed": 12,
"track": 90,
"vertical_rate": 0,
"callsign": "BAW178",
"is_on_ground": true,
"registration": "G-XWBA",
"aircraft_type": "B77W",
"gps_spoofed": false
}
]
}| Field | Type | Required | Null? | Description |
|---|---|---|---|---|
flight_id | string | Yes | Never | Flight UUID |
icao24 | string | null | No | Yes | Aircraft hex |
callsign | string | null | No | Yes | ADS-B callsign |
registration | string | null | No | Yes | Tail number when known |
aircraft_type_icao | string | null | No | Yes | ICAO type code |
departure_airport_icao | string | null | No | Yes | Departure airport ICAO |
departure_airport_iata | string | null | No | Yes | Departure airport IATA |
arrival_airport_icao | string | null | No | Yes | Arrival airport ICAO |
arrival_airport_iata | string | null | No | Yes | Arrival airport IATA |
takeoff_time | string | null | No | Yes | Takeoff time bounding the track (ISO 8601) |
landing_time | string | null | No | Yes | Landing time bounding the track (ISO 8601) |
count | integer | Yes | Never | Number of items in positions |
positions | array | Yes | Never | Position snapshots (newest-first) |
Position snapshot (positions[])
Same field names as live ADS-B positions. JSON path: positions[].
| Field | Type | Required | Null? | Description |
|---|---|---|---|---|
timestamp | string | Yes | Never | Observation time (ISO 8601) |
icao24 | string | Yes | Never | Aircraft hex |
latitude | number | Yes | Never | WGS-84 latitude (decimal degrees) |
longitude | number | Yes | Never | WGS-84 longitude (decimal degrees) |
altitude_baro | number | null | No | Yes | Barometric altitude in feet MSL |
ground_speed | number | null | No | Yes | Ground speed in knots |
track | number | null | No | Yes | Track heading in degrees true |
vertical_rate | number | null | No | Yes | Vertical rate in feet per minute |
callsign | string | null | No | Yes | ADS-B callsign at this snapshot |
is_on_ground | boolean | Yes | Never | true when the aircraft was on the ground |
registration | string | null | No | Yes | Tail number when known |
aircraft_type | string | null | No | Yes | ICAO type code when known |
gps_spoofed | boolean | null | No | Yes | Whether this snapshot was flagged as GPS-spoofed |
Track integration
Replay a gate-to-gate position track for map display. The example below chains from a search result: it takes a flight_id, fetches the track with a 45-second read timeout (large tracks can be slow), downsamples to every 5th position for web map performance, and handles 404 when a flight falls outside the retention window.
import osimport requestsBASE = "https://data.skylinkapi.com/v3.1"HEADERS = { "x-api-key": os.getenv("SKYLINK_API_KEY") or os.getenv("SKYLINK_API_KEY", "YOUR_API_KEY")}def fetch_flight_track(flight_id: str, *, tier: str = "ultra") -> dict: r = requests.get( f"{BASE}/{tier}/history/flight/{flight_id}/track", headers=HEADERS, timeout=(10, 30), ) r.raise_for_status() return r.json()def search_one_flight(*, callsign: str = "BAW178", tier: str = "ultra") -> dict | None: r = requests.get( f"{BASE}/{tier}/history/flights", headers=HEADERS, params={"callsign": callsign, "limit": 1}, timeout=(10, 25), ) r.raise_for_status() flights = r.json().get("flights") or [] return flights[0] if flights else Noneif __name__ == "__main__": import json hit = search_one_flight() if not hit: print("No flight found") else: track = fetch_flight_track(hit["flight_id"]) print(json.dumps({"count": track.get("count"), "positions": len(track.get("positions") or [])}, indent=2))Important: Track and position history return positions newest-first. Reverse chronologically for map replay. At 5-second sampling, a 10-hour flight is ~7,200 points — downsample for web maps.
Your SkyLink licence key, for keys bought direct from skylinkapi.com.
In: header
Path Parameters
Query Parameters
Max position rows (default 2000, max 5000)
20001 <= value <= 5000Response Body
application/json
application/json
curl -X GET "https://data.skylinkapi.com/v3.1/ultra/history/flight/00000000-0000-0000-0000-000000000001/track"null{
"detail": [
{
"loc": [
"string"
],
"msg": "string",
"type": "string",
"input": null,
"ctx": {}
}
]
}Your SkyLink licence key, for keys bought direct from skylinkapi.com.
In: header
Path Parameters
Query Parameters
Max position rows (default 5000, max 10000)
50001 <= value <= 10000Response Body
application/json
application/json
curl -X GET "https://data.skylinkapi.com/v3.1/mega/history/flight/00000000-0000-0000-0000-000000000001/track"null{
"detail": [
{
"loc": [
"string"
],
"msg": "string",
"type": "string",
"input": null,
"ctx": {}
}
]
}