# Vertical Weather API: integration notes

These notes summarise the guides at https://verticalweather.com for tools and
coding agents. The full contract is https://verticalweather.com/openapi.json.

API origin: https://api.verticalweather.com
Status: free beta. Keys come from https://api.verticalweather.com/dashboard.

## What it does

One endpoint returns the atmosphere above a point at a given time: wind,
temperature, pressure, humidity and air density at 1 to 32 heights, from NOAA's
GFS model. Coverage is worldwide, from about ten days in the past to 14 days
ahead. There is no historical (ERA5) data, no trajectory calculation and no
vertical wind.

## Authentication

Send the key in the `X-API-Key` header. Keys belong on a server: don't put them
in browser code, mobile apps or public repositories. `GET /v1/atmosphere/usage`
returns the remaining daily allowance.

## Request

`POST /v1/atmosphere/profile` with JSON:

- `latitude`, `longitude`: decimal degrees.
- `time`: ISO 8601 with a timezone, e.g. `2026-10-03T18:00:00Z`.
- `altitudes_m`: 1 to 32 different heights in metres.
- `altitude_reference`: `agl` (above ground) or `msl` (above sea level). Keep the
  one the user asked for; the two differ by the ground elevation.
- Optional `ground_elevation_m_msl`: the site's elevation, used for `agl`.

Unknown fields and timestamps without a timezone are rejected. Check
`GET /v1/atmosphere/capabilities` (no key needed) for the current coverage and
limits.

## Response

Every value is in SI units. Each entry in `levels` has:

- `altitude_agl_m`, `altitude_msl_m`: metres.
- `wind_u_ms` (towards east), `wind_v_ms` (towards north), `wind_speed_ms`: m/s.
- `wind_direction_deg`: where the wind comes from, clockwise from true north.
  At zero speed it is 0, which then means calm, not north.
- `temperature_k` (kelvin), `pressure_pa` (pascals),
  `specific_humidity_kg_kg`, `relative_humidity_pct` (can exceed 100),
  `density_kg_m3` (moist air, excluding cloud water).

`valid_time` is the model time step actually used; it can differ from
`requested_time`. `provenance` names the model run, grid point, methods and NOAA
attribution. Keep it with stored data.

## Heights that aren't available

Very low heights (0 or 10 m above ground) are usually below the model's lowest
usable level. If any requested height is outside the available column, the API
returns `409` with a `coverage` object giving the available range. Show that to
the user or pick heights inside it; don't substitute values from elsewhere.

## Errors and retries

Errors are `application/problem+json` with `code` and `request_id`.

| Status | Code | What to do |
| --- | --- | --- |
| 400 | `invalid_request` | Fix the request. |
| 401 | `unauthorized` | Check the key. |
| 404 | `outside_coverage` | Choose a time within coverage. |
| 409 | `profile_out_of_range` | Choose heights inside `coverage`. |
| 429 | `rate_limited` | Wait for `Retry-After` seconds. |
| 502 | `upstream_unavailable` | NOAA data unavailable; retry later. |
| 503 | `source_busy`, `service_unavailable` | Wait for `Retry-After` seconds. |

Limits per account: 5 requests per second, 60 per minute, and 100 data fetches
per UTC day (cached results don't count towards the daily figure).

Set a total timeout that includes reading the body. A timeout doesn't mean the
server did no work, so retry at most once or twice, and only after `429`, `503`,
`502` or a network error.

## Clients

TypeScript and Python clients will be published as `vertical-weather` on npm and
PyPI. Until then, call the HTTP API directly.
