API preview

Everything on this site — obs, forecasts, soundings, ladders, edges, history — is served as JSON from /v1. No key or account is required for the free scanner today. A supported external API is coming soon; the web app runs on these exact routes now.

ACCESS
Free preview

No authentication and no published rate limit. CORS is open to every origin, so you can call it straight from a browser while the API product is in preview. Please cache aggressively — the upstream feeds (Open-Meteo, Kalshi, Polymarket) are shared public infrastructure.

DATA PROVENANCE
Current weatheropen-meteo.com
Modelsopen-meteo.com
Best-match forecastopen-meteo.com
MarketsKalshi · Polymarket
Balloon soundingsgenerated

Authentication

There is none for the free preview. Send the request. An Authorization header is accepted and ignored, so client libraries written against a keyed build keep working.

curl "https://<your-host>/v1/markets?min_edge_c=10&venue=kalshi"
GET

/v1/markets

All tracked markets with live obs, the selected forecast, market-implied temperature and the best-trade edge. This is the scanner as JSON — the site polls this exact route.

PARAM
TYPE
DESCRIPTION
venue
string
kalshi · polymarket · all (default)
min_edge_c
int
only markets with best-bucket edge ≥ n cents
station
string
filter by ICAO, e.g. KNYC
day
string
today · next · all (default)
sort
string
edge (default) · volume · gap
forecast_source
string
open_meteo (default) · sonde · ecmwf · gfs · icon
baseline
string
sonde/raw (default) · blend — haircuts edge toward consensus
q
string
free-text match on city, ICAO, title or ticker
view
string
full — returns the internal view model the UI renders
{
  "as_of": "2026-07-29T20:12:04Z",
  "count": 14,
  "venues": [
    { "venue": "kalshi", "ok": true, "count": 9 },
    { "venue": "polymarket", "ok": true, "count": 2 }
  ],
  "markets": [
    {
      "ticker": "KXHIGHNY-26JUL29",
      "venue": "kalshi",
      "station": "KNYC",
      "type": "daily_high",
      "closes_at": "2026-07-30T04:00:00Z",
      "obs": { "temp_f": 91.3, "at": "2026-07-29T19:51:00Z", "trend_f_hr": 0.6,
               "source": "open-meteo" },
      "forecast": {
        "high_f": 92.1, "sigma_f": 0.7, "updated_at": "2026-07-29T19:58:00Z",
        "peak_local": "4:40 PM",
        "components": { "model_consensus_f": 91.0,
                        "obs_bias_f": 0.62, "balloon_nudge_f": 0.48 }
      },
      "consensus": { "open_meteo": 90.0, "ecmwf": 91.2, "gfs": 90.5, "icon": 90.1 },
      "selected_forecast": { "source": "open_meteo", "label": "Open-Meteo",
                             "high_f": 90.0, "sigma_f": 1.4 },
      "market_implied_f": 90.8,
      "gap_f": -0.8,
      "edge": { "bucket": "91–92°", "side": "yes", "price_c": 38, "fair_c": 52,
                "edge_c": 14, "ev_pct": 37, "kelly_quarter_pct": 4.8 },
      "volume_usd": 1240000,
      "open_interest_usd": 3100000,
      "spread_c": 1,
      "liquidity_grade": "A",
      "sonde_obs_age_s": 840,
      "simulated": { "balloon_network": true, "market_book": false }
    }
  ]
}
GET

/v1/markets/{ticker}

Everything in /v1/markets plus the full bucket ladder. Pass forecast_source to switch the selected probability, fair price and edge lens. Sonde probability remains included for comparison.

PARAM
TYPE
DESCRIPTION
forecast_source
string
open_meteo (default) · sonde · ecmwf · gfs · icon
{
  "as_of": "2026-07-29T20:12:04Z",
  "market": {
    "ticker": "KXHIGHNY-26JUL29",
    "selected_forecast": { "source": "open_meteo", "label": "Open-Meteo", "high_f": 91.8 },
    "ladder": [
      { "bucket": "≤88°",   "low_f": null, "high_f": 88,
        "price_c": 6, "selected_prob": 0.0242, "selected_fair_c": 2,
        "selected_edge_c": -4, "sonde_prob": 0.0184 },
      { "bucket": "91–92°", "low_f": 91,   "high_f": 92,
        "price_c": 38, "selected_prob": 0.4475, "selected_fair_c": 45,
        "selected_edge_c": 7, "sonde_prob": 0.5216 }
    ],
    "hourly": { "sonde": { "14": 90.6, "15": 91.5, "16": 92.1 },
                "observed": { "14": 90.7, "15": 91.3 },
                "open_meteo": { "14": 89.2, "15": 90.0 } },
    "sounding": { "unit": "SONDE-7", "simulated": true }
  }
}
GET

/v1/stations/{icao}/obs

Latest Open-Meteo current weather plus one value per elapsed local hour. Real public weather data — not Sonde proprietary telemetry.

{
  "station": { "icao": "KNYC", "name": "Central Park",
               "lat": 40.779, "lon": -73.969, "timezone": "America/New_York" },
  "observation": {
    "at": "2026-07-29T19:51:00Z",
    "tempF": 91.3, "dewpointF": 68.0, "humidityPct": 47,
    "windMph": 9.3, "windDir": "SW", "sky": "Mostly Clear",
    "pressureInHg": 29.92, "pressureTrend": "falling",
    "trendFPerHour": 0.6,
    "todayHighF": 91.3, "todayLowF": 76.2,
    "hourlyF": { "8": 81.0, "9": 82.8, "15": 91.3 },
    "source": "open-meteo"
  },
  "simulated": false
}
GET

/v1/forecast/{icao}

The Sonde forecast for both market types, with its components broken out — model consensus, observation bias correction, and the simulated balloon contribution — alongside every public model's hourly curve.

PARAM
TYPE
DESCRIPTION
date
string
local calendar date, YYYY-MM-DD (default: today)
{
  "station": { "icao": "KNYC", "timezone": "America/New_York" },
  "date": "2026-07-29",
  "sonde": {
    "daily_high": {
      "value_f": 92.1, "sigma_f": 0.7,
      "peak_local": "4:40 PM", "peak_window_local": "3:47 PM–5:33 PM",
      "components": { "model_consensus_f": 91.0,
                      "obs_bias_f": 0.62, "balloon_nudge_f": 0.48 }
    },
    "overnight_low": { "value_f": 74.8, "sigma_f": 0.9 }
  },
  "models": {
    "ecmwf": { "high_f": 91.2, "run": "12Z run", "run_age_h": 8 },
    "gfs":   { "high_f": 90.5, "run": "18Z run", "run_age_h": 4 }
  },
  "sources": { "models": "open-meteo.com (ECMWF IFS / GFS / ICON)",
               "current_weather": "open-meteo.com",
               "open_meteo_best": "open-meteo.com best_match",
               "balloon_network": "SIMULATED" }
}
GET

/v1/soundings/latest

The balloon profile nearest a station, or the whole fleet with no near. Simulated — this deployment operates no fleet. Values are generated deterministically and anchored to the live observation, and every response says so.

PARAM
TYPE
DESCRIPTION
near
string
station ICAO, e.g. KNYC — omit for the full fleet
{
  "notice": "SIMULATED. This deployment operates no balloon fleet…",
  "sounding": {
    "unit": "SONDE-7",
    "station": "KNYC",
    "launched_at": "2026-07-29T17:42:00Z",
    "next_launch_at": "2026-07-29T21:00:00Z",
    "distance_mi": 3.1,
    "bearing": "NE",
    "profile_age_min": 14,
    "surface": { "temp_f": 92.0, "dewpoint_f": 67, "humidity_pct": 44,
                 "wind_mph": 11, "feed": "2-s telemetry" },
    "delta_vs_station_f": 0.7,
    "levels_summary": {
      "t_925mb_c": 26.1,
      "mixed_layer_depth_km": 1.9,
      "lapse_0_1km_c_km": 9.6,
      "low_level_rh_pct": 38
    },
    "delta_vs_open_meteo": { "t_925mb_c": 1.9, "mixed_layer_depth_km": 0.6 },
    "fresher_than_open_meteo_h": 5.7,
    "simulated": true
  }
}
GET

/v1/performance

MAE by source, calibration, Brier scores and the cumulative backtest. Resolved values are real. Issued forecasts are archived from the moment this deployment starts; archived days are scored for real, and only days predating the archive are reconstructed.

PARAM
TYPE
DESCRIPTION
days
int
lookback window, 1–92 (default 90)
{
  "notice": "Resolved values are real … Historical forecasts are SIMULATED …",
  "days": 90,
  "simulated_forecasts": true,
  "forecast_source_coverage": { "archived_days": 14, "simulated_days": 76 },
  "mae_by_source": [
    { "name": "Sonde", "maeF": 1.07, "isSonde": true },
    { "name": "ECMWF", "maeF": 1.63 }
  ],
  "calibration": [ { "sayPct": 50, "happensPct": 51.7, "samples": 240 } ],
  "brier": { "sonde": 0.118, "market": 0.154 },
  "pnl": { "final_usd": 12480, "bankroll_usd": 10000 }
}
GET

/v1/resolutions

Settled station-days: what resolved, what each source called, and how the strategy would have settled.

PARAM
TYPE
DESCRIPTION
days
int
lookback window (default 90)
station
string
filter by ICAO
{
  "count": 12,
  "resolutions": [
    { "date": "2026-07-28", "market": "New York · daily high", "icao": "KNYC",
      "sondeF": 91.4, "impliedF": 90.2, "resolvedF": 91,
      "errSonde": 0.4, "errMarket": 0.8, "result": "WIN", "pnlUsd": 212 }
  ]
}
SSE

/v1/stream

Push channel for obs ticks and edge changes ≥2¢. The original spec called for a WebSocket; this deployment targets serverless hosting where a route handler can’t hold a socket, so it ships as Server-Sent Events — same one-way semantics, works through any proxy, and consumable with a one-line EventSource. Connections are capped at five minutes; reconnect when the stream ends.

PARAM
TYPE
DESCRIPTION
channels
string
comma list: edges, obs:KNYC (default: edges)
min_edge_c
int
only push markets at or above this edge
station
string
restrict edge pushes to one ICAO
interval_ms
int
poll cadence, floor 5000 (default 15000)
const es = new EventSource(
  "https://<your-host>/v1/stream?channels=edges,obs:KNYC&min_edge_c=8"
);

es.addEventListener("edges", (e) => {
  const { markets } = JSON.parse(e.data);   // only markets whose edge moved ≥2¢
  console.log(markets[0].edge);
});

es.addEventListener("obs", (e) => console.log(JSON.parse(e.data)));

Errors

Failures are explicit. A dead upstream returns 502 naming the feed rather than an empty success — if a panel is missing, the API will say why, and /v1/diagnostics reports every feed at once.

{ "error": "observation feed unavailable for KNYC: api.open-meteo.com returned 503" }