METAR
METAR (регулярные метеорологические сводки по аэродрому) — это наблюдения за приземной погодой на конкретном аэродроме или станции. Стандартные сводки METAR выпускаются через регулярные интервалы (обычно каждый час или каждые полчаса), а специальная сводка (SPECI) выпускается при значительном изменении условий на станции с персоналом. Каждая сводка METAR содержит ключевые метеорологические данные: температуру, скорость и направление ветра, видимость, облачность и атмосферное давление. Пилоты, авиадиспетчеры, диспетчеры по обеспечению полётов и метеорологи используют эти сводки для оценки погоды в аэропорту при планировании полётов, навигации и принятии оперативных решений.
Запрос
Требования
x-api-key в каждом запросе (прямая подписка). Подробнее →Отправьте запрос GET с кодом ICAO аэропорта в пути. Необязательные query-флаги управляют декодированием.
https://data.skylinkapi.com/v3.1/weather/metar/{icao}| Параметр | Тип | Обязательный | По умолчанию | Описание |
|---|---|---|---|---|
icao | string | Да | - | Четырёхбуквенный код ICAO — поиск, например KJFK |
parsed | boolean | Нет | false | Добавить декодированные поля под ключом parsed |
Ответ
Исходный ответ (по умолчанию)
{
"raw": "METAR KJFK 062251Z 24017G23KT 10SM FEW060 FEW075 SCT110 BKN180 BKN250 28/17 A2974 RMK AO2 SLP072 T02830167 $",
"icao": "KJFK",
"airport_name": "John F. Kennedy International Airport",
"timestamp": "2026-06-06T23:09:37Z"
}| Поле | Тип | Обязательный | Описание |
|---|---|---|---|
raw | string | Да | Полная строка METAR в исходном виде |
icao | string | Да | Код ICAO |
airport_name | string | Да | Название аэропорта |
timestamp | string (ISO 8601) | Да | Время получения данных API — не время наблюдения |
Декодированный ответ (parsed=true)
{
"raw": "METAR KJFK 062251Z 24017G23KT 10SM FEW060 FEW075 SCT110 BKN180 BKN250 28/17 A2974 RMK AO2 SLP072 T02830167 $",
"icao": "KJFK",
"airport_name": "John F. Kennedy International Airport",
"timestamp": "2026-06-06T23:09:37Z",
"parsed": {
"time": "2026-06-07T00:51:00+02:00",
"wind": {
"direction": 240,
"speed": 17,
"gust": 23,
"variable": []
},
"visibility": {
"value": 10,
"repr": "10"
},
"clouds": [
{ "type": "FEW", "base": 60, "repr": "FEW060" },
{ "type": "FEW", "base": 75, "repr": "FEW075" },
{ "type": "SCT", "base": 110, "repr": "SCT110" },
{ "type": "BKN", "base": 180, "repr": "BKN180" },
{ "type": "BKN", "base": 250, "repr": "BKN250" }
],
"temperature": 28,
"dewpoint": 17,
"altimeter": 29.74,
"flight_rules": "VFR",
"wx_codes": [],
"remarks": "RMK AO2 SLP072 T02830167 $",
"density_altitude": 1792,
"pressure_altitude": 193,
"relative_humidity": 0.49
}
}| Поле | Тип | Обязательный | Описание |
|---|---|---|---|
parsed | object | Да (при parsed=true) | Отсутствует при parsed=false — а не равен null |
parsed.time | string (ISO 8601) | Да | Время наблюдения из заголовка METAR — используйте его для определения возраста данных, а не timestamp |
parsed.wind.direction | integer | Да | Градусы (истинные). 0 при штиле или если направление не сообщается |
parsed.wind.speed | integer | Да | Узлы. Никогда не null — 0 означает штиль |
parsed.wind.gust | integer | null | Да (ключ присутствует всегда) | Узлы. null, если порывов нет (а не 0) |
parsed.wind.variable | integer[] | Да | Диапазон направлений при переменном ветре, например [180, 270]. [], если ветер не переменный |
parsed.visibility.value | number | null | Да (ключ присутствует всегда) | Сухопутные мили. null для P6SM (> 6 SM) — трактуйте как «> 6» |
parsed.visibility.repr | string | Да | Исходный токен из METAR |
parsed.clouds | array | Да | Слои от нижнего к верхнему. [] при ясном небе |
parsed.clouds[].type | string | Да (для каждого элемента) | Коды облачности |
parsed.clouds[].base | integer | Да (для каждого элемента) | Сотни футов AGL. 60 = 6000 ft |
parsed.clouds[].repr | string | Да (для каждого элемента) | Исходный токен. BKN050CB = кучево-дождевые облака на 5000 ft |
parsed.temperature | number | Да | °C |
parsed.dewpoint | number | Да | °C |
parsed.altimeter | number | Да | Установка высотомера QNH в inHg |
parsed.flight_rules | string | Да | Категория полётных условий (VFR, MVFR, IFR, LIFR) |
parsed.wx_codes | array | Да | Текущая погода. [], если явлений нет, — см. Коды текущей погоды |
parsed.remarks | string | Да | Всё, что следует после RMK в исходной строке |
parsed.density_altitude | integer | Да | Футы — эффективная высота с поправкой на температуру и давление; важна для лётных характеристик ВС |
parsed.pressure_altitude | integer | Да | Футы — высота относительно стандартной атмосферы |
parsed.relative_humidity | number | Да | Десятичная дробь от 0 до 1 |
Схемы объектов и допустимость null
При parsed=true объект parsed всегда содержит все ключи — при отсутствии данных ничего не опускается. В зависимости от поля используется null, 0 или []. Без parsed=true ключ parsed отсутствует (а не равен null).
| Ситуация | Что вы получите | Но не это |
|---|---|---|
| Нет порывов | wind.gust: null | отсутствующий ключ или 0 |
| Штиль | wind.direction: 0, wind.speed: 0 | null, отсутствующий ключ |
| Ветер не переменный | wind.variable: [] | null |
Видимость > 6 SM (P6SM) | visibility.value: null, visibility.repr: "P6" | value: 0 |
| Нет текущих явлений погоды | wx_codes: [] | null, отсутствующий ключ |
Ясное небо (SKC/CLR) | clouds: [] | null, отсутствующий ключ |
Схемы вложенных объектов (ветер, видимость, облачность, текущая погода)Развернуть раздел
Ветер
Путь в JSON: parsed.wind. Всегда присутствует как объект.
| Поле | Тип | Обязательный | Null? | Если пусто |
|---|---|---|---|---|
direction | integer | Да | Никогда | 0 = штиль или направление не указано |
speed | integer | Да | Никогда | 0 = штиль |
gust | integer | null | Да | Да | null, если в METAR нет порывов |
variable | integer[] | Да | Никогда | [], если ветер не переменный; [180, 270], если в исходной строке 180V270 |
Видимость
Путь в JSON: parsed.visibility. Всегда присутствует как объект.
| Поле | Тип | Обязательный | Null? | Если пусто |
|---|---|---|---|---|
value | number | null | Да | Да | null для P6SM — трактуйте как «> 6». В остальных случаях число |
repr | string | Да | Никогда | Исходный токен: "10", "3", "P6" и т. д. |
Слои облачности
Путь в JSON: parsed.clouds[]. Всегда массив (может быть пустым).
| Поле | Тип | Обязательный | Null? | Описание |
|---|---|---|---|---|
type | string | Да | Никогда | Коды облачности |
base | integer | Да | Никогда | Сотни футов AGL |
repr | string | Да | Никогда | Исходный токен, например BKN050CB |
Коды текущей погоды
Путь в JSON: parsed.wx_codes[]. Всегда массив (может быть пустым). Если сообщаются текущие явления погоды, каждый элемент содержит оба ключа:
| Поле | Тип | Обязательный | Null? | Описание |
|---|---|---|---|---|
repr | string | Да | Никогда | Исходный токен, например -RA, TSRA |
value | string | Да | Никогда | Расшифровка, например Light Rain, Thunderstorm Rain |
Пример из рабочего API (KORD):
"wx_codes": [{ "repr": "-RA", "value": "Light Rain" }]Клиентские типы
Скопируйте в свой проект. Допустимость null соответствует разделу Схемы объектов и допустимость null выше.
"""METAR response and summary types - matches weather-metar field tables."""from __future__ import annotationsfrom dataclasses import dataclassfrom typing import LiteralFlightRules = Literal["VFR", "MVFR", "IFR", "LIFR"]@dataclassclass MetarRequest: """Path/query input for GET /weather/metar/{icao}.""" icao: str parsed: bool = False@dataclassclass MetarWind: direction: int speed: int gust: int | None variable: list[int]@dataclassclass MetarVisibility: value: float | None repr: str@dataclassclass MetarCloudLayer: type: str base: int repr: str@dataclassclass MetarWxCode: repr: str value: str@dataclassclass MetarParsed: time: str wind: MetarWind visibility: MetarVisibility clouds: list[MetarCloudLayer] temperature: float dewpoint: float altimeter: float flight_rules: FlightRules wx_codes: list[MetarWxCode] remarks: str density_altitude: int pressure_altitude: int relative_humidity: float@dataclassclass MetarResponse: raw: str icao: str airport_name: str timestamp: str parsed: MetarParsed | None = None@dataclassclass MetarSummary: """Shape returned by metar_summary() in the fetch example.""" icao: str category: FlightRules wind_kt: int gust_kt: int | None visibility_display: str age_min: float stale: boolТипы данных (MetarResponse, MetarParsed) повторяют JSON ответа с parsed=true. MetarSummary определён в начале каждой вкладки примера кода.
Интеграция
Получение, кэширование и сводка наблюдений — следующий шаг после разбора успешного ответа.
Пример кэширует каждую сводку METAR на пять минут (наблюдения обновляются не чаще чем раз в 30–60 минут), использует таймауты 10 s / 15 s на подключение/чтение и строит сводку по parsed.time (время наблюдения), а не по timestamp (время запроса к API).
import osimport timefrom dataclasses import dataclassfrom datetime import datetime, timezonefrom typing import Literalimport requests# MetarSummary - helper return type. Full wire types (MetarResponse, MetarParsed, …)# are in the Client types section on the METAR docs page.FlightRules = Literal["VFR", "MVFR", "IFR", "LIFR"]@dataclassclass MetarSummary: icao: str category: FlightRules wind_kt: int gust_kt: int | None visibility_display: str age_min: float stale: boolHEADERS = { "x-api-key": os.getenv("SKYLINK_API_KEY", "YOUR_API_KEY")}BASE = "https://data.skylinkapi.com/v3.1"CACHE: dict[str, tuple[dict, float]] = {}METAR_TTL = 300 # 5 min - safe inside the 30–60 min observation cycledef parse_observation_time(iso: str) -> datetime: """Parse parsed.time - API returns ISO 8601 with timezone offset.""" return datetime.fromisoformat(iso.replace("Z", "+00:00"))def fetch_metar(icao: str) -> dict | None: cache_key = f"metar:{icao}:parsed" cached = CACHE.get(cache_key) if cached and time.time() < cached[1]: return cached[0] try: r = requests.get( f"{BASE}/weather/metar/{icao}", headers=HEADERS, params={"parsed": "true"}, timeout=(10, 15), ) except requests.Timeout as exc: raise RuntimeError(f"SkyLink timeout fetching METAR for {icao}") from exc if r.status_code == 404: return None r.raise_for_status() data = r.json() CACHE[cache_key] = (data, time.time() + METAR_TTL) return datadef metar_summary(icao: str) -> MetarSummary | None: metar = fetch_metar(icao) if not metar: return None p = metar["parsed"] obs = parse_observation_time(p["time"]) age_min = (datetime.now(timezone.utc) - obs).total_seconds() / 60 vis = p["visibility"]["value"] return MetarSummary( icao=icao, category=p["flight_rules"], wind_kt=p["wind"]["speed"], gust_kt=p["wind"]["gust"], visibility_display=f"{vis} SM" if vis is not None else "> 6 SM", age_min=round(age_min, 1), stale=age_min > 90, )if __name__ == "__main__": import json from dataclasses import asdict summary = metar_summary("KJFK") print(json.dumps(asdict(summary), indent=2) if summary else "METAR not available")Другие примеры: Сценарии использования погодных данных.
Примечания по реализации
timestamp и parsed.time. timestamp меняется при каждом запросе. parsed.time — время наблюдения из заголовка METAR; используйте его для сообщений вида «данным X минут».
visibility.value равно null. Если станция сообщает P6SM, value равно null, а repr — "P6". Трактуйте null как «> 6 SM», а не как отсутствие данных.
Доступность станций. Не для каждого кода ICAO есть станция METAR. Ответ 404 означает, что наблюдение недоступно, — сам аэропорт при этом может существовать. Показывайте пустое состояние, а не баннер с ошибкой.
Кэширование. Клиентский кэш на 3–5 минут сокращает дублирующиеся вызовы, не пропуская новых наблюдений.
Ответы с ошибками
Здесь описаны только сбои, специфичные для METAR. Ошибки аутентификации, валидации, ограничения частоты запросов и ошибки сервера описаны в разделе Обработка ошибок. Паттерны резервного перехода между METAR и TAF см. в разделе Когда погодные данные отсутствуют.
404 — нет METAR для этого кода ICAO
{
"detail": "Airport not found for ICAO code: KXYZ"
}Аэропорт может не существовать либо существовать, но не иметь станции METAR. Сообщение не различает эти случаи — трактуйте любой ответ 404 для METAR как отсутствие доступного наблюдения.
Your SkyLink licence key, for keys bought direct from skylinkapi.com.
In: header
Path Parameters
4-letter ICAO airport code
4 <= length <= 4Query Parameters
Include parsed/decoded METAR fields alongside raw text
falseResponse Body
application/json
application/json
curl -X GET "https://data.skylinkapi.com/v3.1/weather/metar/KJFK"{
"raw": "METAR KJFK 271851Z 16013KT 10SM FEW024 15/09 A3020 RMK AO2 SLP216 T01500089",
"icao": "KJFK",
"airport_name": "John F Kennedy International Airport",
"timestamp": "2025-09-27T12:00:00Z"
}{
"detail": [
{
"loc": [
"string"
],
"msg": "string",
"type": "string",
"input": null,
"ctx": {}
}
]
}См. также: TAF · Сценарии использования · Ошибки · Продакшн