Kalshi Weather Markets + NWS Station Data [$0.02/city-day] avatar

Kalshi Weather Markets + NWS Station Data [$0.02/city-day]

Pricing

from $20.00 / 1,000 ladder + nws station data

Go to Apify Store
Kalshi Weather Markets + NWS Station Data [$0.02/city-day]

Kalshi Weather Markets + NWS Station Data [$0.02/city-day]

Every Kalshi daily high and low temperature market (24 US cities) joined to the NWS station that settles it: the full strike ladder with prices and implied probabilities, observations so far today, the daily and hourly forecast, and the official climate report. Free official APIs only.

Pricing

from $20.00 / 1,000 ladder + nws station data

Rating

0.0

(0)

Developer

Perch Data

Perch Data

Maintained by Community

Actor stats

0

Bookmarked

2

Total users

1

Monthly active users

17 hours ago

Last modified

Categories

Share

Kalshi Weather Markets + NWS Station Data

One JSON row per Kalshi daily temperature ladder (a city, a day, high or low), with everything an agent needs to price it in a single call:

  • The ladder: every strike as Kalshi lists it (78° or below, 79° to 80°, ... 87° or above) with the integer Fahrenheit bounds worked out, YES bid, ask, mid, last, volume, open interest, and status. Settled ladders carry each strike's yes/no result.
  • The market's view: each strike's probability normalised so the ladder sums to one, the favourite, the probability-weighted expected temperature, and how far the raw YES prices sum above one.
  • The station that settles it: Kalshi's rules name an NWS climate site (Central Park for NYC, Midway for Chicago, and so on). The row joins that station from api.weather.gov: observations recorded so far on the target day with the running max and min, the NWS daily forecast high and low for that day, the hourly forecast's max and min, and the official climate report (CLI) once it is issued.
  • The comparison: which strike the forecast lands on and what the market charges for it, which strike the running observation is in, which strike the official report settles, and the forecast minus the market's expected temperature.

24 US cities as of September 2026: New York (Central Park and Newark), Chicago, Miami, Austin, Denver, Los Angeles, Philadelphia, Atlanta, Boston, Dallas, Washington, Houston, Las Vegas, Minneapolis, New Orleans, Oklahoma City, Phoenix, San Diego, San Antonio, Louisville, San Francisco, Seattle, Trenton. Kalshi's international cities (London, Paris, Tokyo, ...) settle on The Weather Company with no NWS station; those ladders are returned plain and never charged as enriched.

Both sources are official, free, documented JSON APIs. Nothing is scraped, nothing is guessed, missing values are null.

Why the join

Kalshi's temperature markets settle on a specific NWS climate station's daily max or min. Pricing them means knowing that station's forecast, what it has recorded so far today, and, after the fact, what the official report said. The other Kalshi actors on the store return market prices only; the weather actors return weather only, for a coordinate, not for the settlement station. This actor reads the station out of each market's rules text and fetches exactly that station, so the forecast and the strikes are about the same thermometer.

Checked against settlements: across 288 settled ladders over seven days and 24 cities, the official CLI report's max or min landed in the strike Kalshi paid out every time.

Quick start

Every open ladder (today and tomorrow, all cities, high and low), joined to NWS:

{}

New York and Chicago highs only:

{ "kind": "high", "stations": ["NYC", "MDW"] }

Settled ladders for a date range with the official temperature attached, for a training set:

{ "status": "settled", "dateFrom": "2026-09-01", "dateTo": "2026-09-09", "maxEvents": 500 }

Just the ladders, no NWS join, cheapest:

{ "enrich": false, "maxEvents": 200 }

Input

FieldTypeDefaultMeaning
kindboth high lowbothDaily maximum ladders (KXHIGH*), daily minimum ladders (KXLOW*), or both.
statusopen closed settledopenTrading now; past last trade but unsettled; finalized with results.
stationslist of stringsallNWS climate-site codes from Kalshi's rules: NYC, MDW, MIA, AUS, DEN, LAX, PHL, ATL, BOS, DFW, DCA, EWR, HOU, LAS, MSP, MSY, OKC, PHX, SAN, SAT, SDF, SFO, TTN, SEA.
dateFrom, dateToISO datenoneKeep ladders whose target day is in the range. The target day is the local calendar day the temperature is measured on.
maxEventsinteger100Stop after this many ladders. Open ladders on a normal day: about 48.
enrichbooleantrueJoin to the NWS station. Charged as enriched-event instead of event.
includeHourlyPeriodsbooleanfalseKeep every hourly forecast period for the target day in the row.
analysisbooleanfalseAdd a written analysis_text to each enriched row (below). Charged as ladder-analysis on top of enriched-event.
requestDelaySecondsnumber0.25Delay between requests to either API.
archiveDatasetNamestringnoneAlso append every row to this named dataset in your account, for a history that outlives run retention. Not charged again.

Output

One row per ladder. Every field below is present on every row; values are null when the source has nothing.

Top level

FieldMeaning
event_tickerKalshi event, e.g. KXHIGHNY-26SEP11.
series_ticker, series_titleThe city's series, e.g. KXHIGHNY, "Highest temperature in NYC".
kindhigh or low.
target_dateThe local calendar day the temperature is measured on (from the ticker).
strike_dateKalshi's settlement timestamp.
station{cli_id, icao, city} read from the rules, e.g. {"cli_id": "NYC", "icao": "KNYC", "city": "New York City"}. null for international cities.
settlement_source{name, url} as Kalshi lists it.
rules_primaryKalshi's settlement rule text.
marketsThe strikes, sorted from coldest to warmest (below).
market_summaryThe ladder as a distribution (below).
settlement{value_f, yes_ticker, yes_label} once settled: the temperature Kalshi settled on and the strike that paid out. null while open.
statusThe status you asked for.
event_urlThe Kalshi page.
fetched_at_utcWhen this row was built.
enrichmentThe NWS join (below). Present only when enrich is on.

Each strike in markets

FieldMeaning
ticker, labele.g. KXHIGHNY-26SEP11-B79.5, 79° to 80°.
strike_type, floor_strike, cap_strikeKalshi's raw strike fields.
low_f, high_fInclusive integer Fahrenheit bounds of a YES; null for an open end. The ladder is contiguous: each strike starts one degree after the previous one ends.
yes_bid, yes_ask, yes_mid, last_price, previous_priceDollars per contract, 0 to 1.
implied_probThe YES mid, or the last price if there is no two-sided quote.
normalized_probimplied_prob divided by the ladder's sum, so the strikes add to one.
volume, volume_24h, open_interest, liquidity_dollarsAs reported by Kalshi.
status, resultactive, closed, finalized; result is yes or no once settled, else null.
expiration_valueOnce settled, the number Kalshi settled the ladder on (the official temperature), stamped on every strike. null while open.
open_time, close_time, expected_expiration_time, updated_timeUTC timestamps.

market_summary

FieldMeaning
brackets, pricedStrike count and how many have a price.
prob_sumSum of raw implied_prob across strikes. Above 1 means the ladder is priced rich.
expected_temp_fProbability-weighted temperature using each strike's midpoint (open ends count as half a degree past the edge).
favorite_ticker, favorite_label, favorite_probThe most likely strike and its normalised probability.
total_volume, total_open_interestAcross the ladder.

enrichment

FieldMeaning
statusok, partial (one NWS piece failed; see problems), no_nws_station, station_lookup_failed, fetch_failed. Only ok and partial rows are charged as enriched.
station{icao, name, timezone, lat, lon, grid_id, grid_x, grid_y, forecast_url, forecast_hourly_url, forecast_office} from api.weather.gov.
observationsFor the target day in station local time: count, max_f, max_at, min_f, min_at, latest_f, latest_at, first_at. Fahrenheit to one decimal (NWS reports Celsius). Empty before the day begins.
forecastNWS daily forecast: high_f (the daytime period on the target day), low_f (the overnight period covering the target day's early hours), period names and short text, generated_at, updated_at.
hourly_forecasthours, max_f, max_at, min_f, min_at over the target day's hourly periods; periods when includeHourlyPeriods is on.
climate_reportThe NWS CLI product for the target day, once issued: summary_for, issued_at, issuing_office, max_f, max_at, min_f, min_at, final (false for the afternoon partial, true for the next-morning final), as_of, product_id. null until the first issuance, and null again once NWS's API stops listing it, about seven days later; after that settlement.value_f carries the official number.
analysisforecast, hourly_forecast, running, projected, official: each {temp_f, ticker, label, implied_prob, normalized_prob} for the strike that reading lands on. forecast is the NWS daily figure, or the hourly figure when the daily period for the day has already passed (forecast_source says which). projected is the best current estimate of the day's extreme: the warmer (for highs) or cooler (for lows) of what has been observed so far and what the hourly forecast still expects; it equals the forecast before the day starts and converges on the observation as the day ends. official comes from the climate report while NWS lists it and from Kalshi's stamped settlement value afterwards (official_source says which); official_final mirrors the report's final. market_expected_temp_f, forecast_minus_market_f, and projected_minus_market_f compare those readings to the market.

The temperature Kalshi settles on is the official climate report's whole-degree max or min. Observations are hourly (some stations report more often) and can miss the exact peak minute, so observations.max_f is a floor on the day's high, not the final value.

With analysis: true, each enriched row also carries:

FieldMeaning
analysis_text{text, model, generated_at}: 90 to 140 words written by Claude from the row's own numbers: where the market puts its weight and what it expects, where the NWS forecast and the observations so far land and how far that sits from the market, and what settled if the report is in. It recommends nothing; a null field in the row is reported as missing, never guessed. null when the model could not produce one (that row is not charged the analysis event). Absent when analysis is off or the budget ran out.

Pricing

EventPriceWhat it is
event$0.002One ladder, plain.
enriched-event$0.02One ladder joined to its NWS station.
ladder-analysis$0.10An enriched ladder that also carries a written analysis_text. Charged in addition to enriched-event, only for rows where it is not null.

Apify's free credit covers a few hundred enriched ladders. With a budget set, the actor works out how many ladders it can join, joins those, and returns the rest plain; analyses are capped the same way after the join. Rows without an NWS station are always plain. Nothing is charged for a row that is not returned.

Use it from Zapier or Clay

No code needed; both call the actor with your own Apify account and you pay the per-row prices above. In Zapier, a Schedule trigger (for example 06:00 and 14:00 local), the Apify action Run Actor (synchronous) with { "status": "open", "stations": ["NYC", "MDW", "MIA"], "enrich": true }, then Fetch Dataset Items into a Google Sheet or a Slack channel gives you each open ladder next to the NWS forecast and running observations. In Clay, Import data from Apify Actor with the same input fills a table with one ladder per row.

Wrap this in an afternoon

Reselling these rows behind your own search box is allowed and expected; it is what the per-row price is for. A zero-dependency starter kit does it: a one-page storefront, Stripe credit packs that never expire (no subscription), and one call to this actor per search. Point it at perchpermits/kalshi-weather-markets-nws, set your price per ladder, and deploy anywhere Node runs. Source and setup: wrapper-kit. At $0.02 an enriched ladder here, a $0.10 charge per ladder on your side leaves about 80% before Stripe's fee.

What it refuses to do

If Kalshi's or NWS's payload changes shape, the run fails with a drift error and charges nothing rather than returning empty rows at the enriched price. If every NWS join in a run fails, the whole run fails. Older settled ladders (Kalshi keeps nested markets for roughly the newest two months) are skipped, not invented.

Prices are Kalshi's listed quotes at fetch time, for information only. Kalshi is a regulated US exchange; check your eligibility before trading on any of this.

Source policy

Two official APIs: api.elections.kalshi.com/trade-api/v2 (public read endpoints, no key) and api.weather.gov (public, identifies itself with a contact User-Agent as NWS asks). One request every 0.25 s by default. Station metadata and forecasts are fetched once per station per run, so a full run of 48 ladders is about 100 Kalshi requests and 100 NWS requests.

Same account, other tools: ATP and WTA matches with 15+ bookmakers' odds, form, and head-to-head, Nashville building permits with the licensed contractor attached, and a kitchen floor plan and cabinet takeoff from a JSON room spec.