# Kalshi Weather Markets API - Temperature Odds & NWS Forecast (`neverempty/kalshi-weather-markets-api`) Actor

For weather traders and forecast models: Kalshi temperature, rain and snow markets as rows with bid, ask, volume, open interest and strike range; daily markets add the NWS forecast for the station in the market's rules. All 143 weather series (2026-09-21). Settled history and price-move monitor.

- **URL**: https://apify.com/neverempty/kalshi-weather-markets-api.md
- **Developed by:** [NeverEmpty](https://apify.com/neverempty) (community)
- **Categories:** Developer tools, Automation, Other
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $2.19 / 1,000 market returneds

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.
Since this Actor supports Apify Store discounts, the price gets lower the higher subscription plan you have.

Learn more: https://docs.apify.com/actors/running/actors-in-store.md#pay-per-event

## What's an Apify Actor?

An Actor is a serverless cloud program that runs on the Apify platform. It has two run modes.
In Batch mode, an Actor accepts a well-defined JSON input, performs an action which can take anything from a few seconds to a few hours,
and optionally produces a well-defined JSON output, datasets with results, or files in key-value store.
In Standby mode, an Actor provides a web server which can be used as a website, API, or an MCP server.

Apify vocabulary and the platform model are defined once, in the agent quickstart at https://apify.com/agents.md.

## How to integrate an Actor?

If asked about integration, you help developers integrate Actors into their projects.
You adapt to their stack and deliver integrations that are safe, well-documented, and production-ready.

Do not guess an integration path. Every one of them is in the agent quickstart at https://apify.com/agents.md: the Apify MCP server, Agent Skills with the Apify CLI, the JavaScript and Python clients, the REST API, and the account-free path for an agent with no human to sign in. It also carries the rule on stating cost before the first paid run.

For examples already wired to this Actor's own input schema, see the [API](#api) section below.

Each client library has reference documentation the quickstart does not restate: [JavaScript/TypeScript](https://docs.apify.com/api/client/js/docs.md) (`npm install apify-client`) and [Python](https://docs.apify.com/api/client/python/docs.md) (`pip install apify-client`).

# README

## Kalshi Weather Markets API - Temperature Odds & NWS Forecast

Get every **Kalshi weather market** (daily high and low temperature, rain, snow) as one clean row per market: yes/no bid and ask, last price, volume, open interest, close time and the strike range ("70° to 71°"). Each daily market also carries the **National Weather Service forecast for the weather station named in its rules** (for example CLINYC = New York City, Central Park), and a flag saying whether that forecast falls inside the market's Yes range. Settled history with the official settled value, automatic discovery of all weather series, and a monitoring mode that returns only markets whose price or volume moved.

It reads Kalshi's official public market-data API (`api.elections.kalshi.com/trade-api/v2`) and the NWS API (`api.weather.gov`). No login, no API key, no proxy.

### Why this Actor

- **Reads Kalshi's current field names.** Kalshi now sends prices as `yes_bid_dollars` ("0.4900") and quantities as `volume_fp` ("4039.48"); the old integer fields such as `yes_bid` are no longer in the response (checked 2026-09-21). This Actor reads both the new and the old names, and returns `null` (never 0) when a value is missing, so a format change does not silently turn prices into zeros.
- **Forecast next to the odds.** For each daily temperature, rain and snow market, the settlement station is taken from the market's own rules, and the NWS forecast high, low and precipitation chance for the market's date is added to the same row: `nwsForecastForThisMarketF` and `nwsForecastInYesRange` let you compare the crowd price with the forecast without a second data source.
- **Honest empty results.** A series Kalshi does not have, a series with no open market, a refusal, a rate limit and a cut-off page each come back as a separate free row that says what happened. Kalshi answers an unknown or lowercase series with an empty list (HTTP 200), so the Actor checks the series itself before saying "no markets".

### Input

| Field | Type | Default | What it does |
|---|---|---|---|
| `series` | list | (prefilled: KXHIGHNY, KXLOWTNYC, KXHIGHCHI) | Kalshi series tickers, one per line. Lowercase is accepted. Left out (with discovery and monitoring off), the three example series are read. |
| `discoverSeries` | boolean | false | Also read every Kalshi "Climate and Weather" series of the types below: daily high and low temperature series, and daily, weekly or monthly rain and snow series (143 series on 2026-09-21; most have no open market at a given time, which costs nothing). |
| `weatherTypes` | list | all | Used with `discoverSeries`: `high`, `low`, `rain`, `snow`. |
| `marketStatus` | select | open | `open` (tradable now; Kalshi reports them as `active`), `settled` (with `result` and `settlementValue`), `closed` (trading ended, not settled yet) or `all`. |
| `closedWithinDays` | integer | (none) | For settled, closed and all: only markets whose close time is within the last N days. Ignored for open. Required in monitoring mode with settled, closed or all. |
| `includeForecast` | boolean | true | Attach the NWS forecast of the settlement station to daily temperature, rain and snow markets. No extra charge. |
| `maxResults` | integer | 1000 | Stop after this many market rows (monitoring off). A free row says what was left out. |
| `monitoringMode` | boolean | false | Return only markets whose yes bid, yes ask, last price, volume, open interest, status or result changed since the last run, plus newly opened markets. |
| `resetMonitoringState` | boolean | false | Forget what monitoring remembered, so the next monitoring run returns everything again. Turn it off after one run. |

Examples:

```json
{ "series": ["KXHIGHNY", "KXLOWTNYC"] }
```

```json
{ "discoverSeries": true, "weatherTypes": ["high", "low"] }
```

```json
{ "series": ["KXHIGHNY"], "marketStatus": "settled", "closedWithinDays": 30 }
```

### Daily temperature series and their settlement stations

Read from the market rules on 2026-09-21 (station names from the NWS station list). Kalshi adds and retires series; `discoverSeries` always uses the live list.

| City | Daily high | Daily low | Station in the rules | NWS station |
|---|---|---|---|---|
| New York City | KXHIGHNY | KXLOWTNYC | CLINYC | KNYC Central Park |
| Chicago | KXHIGHCHI | KXLOWTCHI | CLIMDW | KMDW Midway (not O'Hare) |
| Los Angeles | KXHIGHLAX | KXLOWTLAX | CLILAX | KLAX |
| Miami | KXHIGHMIA | KXLOWTMIA | CLIMIA | KMIA |
| Austin | KXHIGHAUS | KXLOWTAUS | CLIAUS | KAUS |
| Denver | KXHIGHDEN | KXLOWTDEN | CLIDEN | KDEN |
| Philadelphia | KXHIGHPHIL | KXLOWTPHIL | CLIPHL | KPHL |
| Houston | KXHIGHTHOU | KXLOWTHOU | CLIHOU | KHOU Hobby (not Bush/IAH) |
| Dallas | KXHIGHTDAL | KXLOWTDAL | CLIDFW | KDFW |
| Phoenix | KXHIGHTPHX | KXLOWTPHX | CLIPHX | KPHX |
| Las Vegas | KXHIGHTLV | KXLOWTLV | CLILAS | KLAS |
| Seattle | KXHIGHTSEA | KXLOWTSEA | CLISEA | KSEA |
| San Francisco | KXHIGHTSFO | KXLOWTSFO | CLISFO | KSFO |
| San Diego | KXHIGHTSAN | KXLOWTSAN | CLISAN | KSAN |
| San Antonio | KXHIGHTSATX | KXLOWTSATX | CLISAT | KSAT |
| Boston | KXHIGHTBOS | KXLOWTBOS | CLIBOS | KBOS |
| Washington DC | KXHIGHTDC | KXLOWTDC | CLIDCA | KDCA Reagan National |
| Atlanta | KXHIGHTATL | KXLOWTATL | CLIATL | KATL |
| Minneapolis | KXHIGHTMIN | KXLOWTMIN | CLIMSP | KMSP |
| New Orleans | KXHIGHTNOLA | KXLOWTNOLA | CLIMSY | KMSY |
| Oklahoma City | KXHIGHTOKC | KXLOWTOKC | CLIOKC | KOKC |
| Louisville | KXHIGHTSDF | KXLOWTSDF | CLISDF | KSDF |
| Newark | KXHIGHTEWR | KXLOWTEWR | CLIEWR | KEWR |
| Trenton | KXHIGHTTTN | KXLOWTTTN | CLITTN | KTTN |

Rain: `KXRAIN` (daily, one market per city, each with its own station) and monthly series such as `KXRAINNYCM`, `KXRAINCHIM`, `KXRAINDENM`.

### Output

One row per market. Example (KXHIGHNY, read 2026-09-21):

```json
{
  "seriesTicker": "KXHIGHNY",
  "seriesTitle": "Highest temperature in NYC",
  "marketKind": "high",
  "eventTicker": "KXHIGHNY-26SEP21",
  "marketTicker": "KXHIGHNY-26SEP21-B70.5",
  "yesLabel": "70° to 71°",
  "strikeType": "between",
  "floorStrike": 70,
  "capStrike": 71,
  "targetDate": "2026-09-21",
  "marketStatus": "active",
  "yesBid": 0.5,
  "yesAsk": 0.51,
  "noBid": 0.49,
  "noAsk": 0.5,
  "yesMid": 0.505,
  "spread": 0.01,
  "lastPrice": 0.49,
  "volume": 4039.53,
  "openInterest": 3317.18,
  "closeTime": "2026-09-22T05:00:00Z",
  "settlementStationCode": "CLINYC",
  "nwsStationId": "KNYC",
  "nwsStationName": "New York City, Central Park",
  "settlementSource": "The Weather Company",
  "nwsForecastHighF": 70,
  "nwsForecastHighPeriod": "Monday",
  "nwsForecastLowF": 59,
  "nwsForecastLowPeriod": "Overnight",
  "nwsPrecipChanceDayPct": 7,
  "nwsForecastForThisMarketF": 70,
  "nwsForecastInYesRange": true
}
```

| Column | Meaning |
|---|---|
| `yesBid`, `yesAsk`, `noBid`, `noAsk`, `lastPrice`, `previousPrice` | USD per contract (a contract pays $1.00). `0` means Kalshi reports no resting bid at any price; `null` means the field was not in the response. |
| `yesMid`, `spread` | Calculated from yes bid and ask, only when both sides have resting orders and the market is not settled; otherwise `null`. When nobody is selling, Kalshi reports the yes ask as 1.00 with size 0 (and the yes bid as 0 with size 0 when nobody is buying), so check `yesAskSize` / `yesBidSize` before reading those prices as quotes. |
| `volume`, `volume24h`, `openInterest`, `yesBidSize`, `yesAskSize` | Contracts. Kalshi allows fractional contracts, so these can have decimals. |
| `strikeType`, `floorStrike`, `capStrike`, `yesLabel` | `greater` = above `floorStrike` (floor 73 is "74° or above"); `less` = below `capStrike` (cap 66 is "65° or below"); `between` = from `floorStrike` to `capStrike`, both included ("72° to 73°"). |
| `targetDate` | The date in the market's event ticker (`-26SEP21` = 2026-09-21). For weekly markets this is the first day of the week the market covers; for monthly markets (`-26SEP`) it is `null`. Forecasts are attached only to daily markets. |
| `result`, `settlementValue`, `settledAt` | For settled markets: `yes`/`no`, the settled value (for example `69` = official high of 69°F) and when it settled. |
| `settlementStationCode`, `nwsStationId` | The station named in the market rules (`CLINYC`) and its NWS station id (`KNYC`). |
| `settlementSource` | The source Kalshi names for settlement in the series (on 2026-09-21: "The Weather Company"). The NWS forecast is a forecast for that station, not the settlement value. |
| `nwsForecastHighF` | NWS forecast high: the daytime period (6 am to 6 pm local) of the market date. |
| `nwsForecastLowF` | NWS forecast low: the night that ends on the morning of the market date (6 pm the day before to 6 am; after midnight NWS calls the rest of it "Overnight"). |
| `nwsPrecipChanceDayPct`, `nwsPrecipChanceNightPct` | Precipitation chance of the daytime period and of the night that starts on the evening of the market date. |
| `nwsForecastForThisMarketF`, `nwsForecastInYesRange` | The forecast high for high markets or the forecast low for low markets, and whether it falls inside the Yes range. `null` for other markets. |
| `nwsForecastNote` | Why a forecast column is `null`: past date, beyond the NWS forecast (about 7 days), a period that has already passed, a market with no station in its rules (hourly markets settle on Synoptic Data), a station outside the US, or `includeForecast` off. |
| `monitorStatus`, `changedFields` | Monitoring mode only: `first-check`, `changed` (with the columns that changed) or `new-market`. |

Rows whose `status` is not `ok` are free and explain themselves in `note`: `unknown-series`, `no-markets`, `duplicate`, `blocked`, `unreadable`, `refused`, `incomplete`, `not-checked`, `budget-reached`, `no-change-since-last-run`, `invalid-input`.

### Pricing

- **$3.00 per 1,000 market rows** returned.
- Monitoring mode adds **$0.30 per 1,000 series checks**: each series whose markets are read costs one check, whether or not anything changed. Unknown series, series with no market and failed requests are not charged.
- The NWS forecast columns cost nothing extra. Free rows (the ones that explain why something was not returned) cost nothing.
- The run stops before it would go over the maximum total charge you set, and a free row says what was left out.

### Monitoring mode

Turn on `monitoringMode` and run the Actor on a schedule (for example every 10 minutes during the trading day). The first run returns every market once as a baseline. Later runs return only markets whose yes bid, yes ask, last price, volume, open interest, status or result changed, plus markets that opened since, with `changedFields` naming what moved. A run with no change returns one free `no-change-since-last-run` row. Markets are remembered per series in a named key-value store; markets you did not receive because the maximum total charge was reached are not remembered, so the next run returns them if they still differ. Do not put the same series in two schedules that can run at the same time (Apify's key-value store has no atomic update).

### Notes and limits

- Kalshi's public API is read at about 6 requests per second; a rate limit (HTTP 429) is waited out and retried, and reported as a free `blocked` row if it persists.
- NWS covers the United States only. Series settled at stations outside the US (for example Tokyo or Paris) get `null` forecasts with the reason.
- This Actor returns market data and forecasts. It does not place orders and is not trading advice.

# Actor input Schema

## `series` (type: `array`):

Kalshi series to read, one per line, for example KXHIGHNY (NYC daily high), KXLOWTNYC (NYC daily low), KXHIGHCHI (Chicago daily high), KXHIGHLAX (Los Angeles daily high) or KXRAIN (daily rain, many cities). Lowercase is accepted. A ticker Kalshi does not have comes back as a free 'unknown-series' row. A repeated series is read and charged once. If you leave this field out (and discoverSeries is off) with monitoring off, three example series are read: KXHIGHNY, KXLOWTNYC and KXHIGHCHI. Up to 300 series per run.

## `discoverSeries` (type: `boolean`):

On = the Actor lists Kalshi's 'Climate and Weather' series and adds every daily high-temperature and low-temperature series, and every daily, weekly or monthly rain and snow series, of the types chosen below (about 140 series on 2026-09-21; many are seasonal, retired or outside the US and have no market of the chosen status, which costs nothing). Series with no market of the chosen status add no rows. Off = only the series in the list above.

## `weatherTypes` (type: `array`):

Used only with discoverSeries: high = daily maximum temperature, low = daily minimum temperature, rain = precipitation, snow = snowfall. Empty = all four.

## `marketStatus` (type: `string`):

open = markets you can trade now (Kalshi reports them as 'active'). settled = finished markets with the result and the settled value (for example the official high of the day). closed = trading ended, not yet settled. all = every market of the series. For settled, closed and all, closedWithinDays limits how far back to go.

## `closedWithinDays` (type: `integer`):

Only markets whose close time is within the last N days. Ignored when marketStatus is open. Required in monitoring mode with settled, closed or all. Leave it empty to read the whole history of the series (a daily series has about 6 to 12 markets per day since it started, so use maxResults to cap it).

## `includeForecast` (type: `boolean`):

On = for daily temperature, rain and snow markets, the Actor reads the weather station named in the market rules (for example CLINYC = New York City, Central Park) and attaches the National Weather Service forecast high and low, precipitation chance and short forecast for the market's date, plus whether the forecast falls inside the market's Yes range. Free of extra charge. Past dates and dates beyond the NWS forecast (about 7 days) get null with the reason in nwsForecastNote.

## `maxResults` (type: `integer`):

With monitoring off, the run stops once this many market rows have been returned, and a free row says what was not returned. Free rows do not count. In monitoring mode it does not limit the changed markets returned: every series in the list is checked, as far as the run's maximum total charge allows.

## `monitoringMode` (type: `boolean`):

Off = every market comes back, charged per row. On = the Actor remembers, per series, each market's yes bid, yes ask, last price, volume, open interest, status and result, and later runs return only markets where one of these changed, plus newly opened markets. The first run returns every market once as a baseline. In monitoring mode every series whose markets are read costs $0.30 per 1,000 checks, changes or not (unknown series, series with no market and failed requests are free), plus the row price for the markets returned. Example: 5 series every 10 minutes = 21,600 checks a month = $6.48, plus the markets that changed. The Actor reads only as many series as the run's maximum total charge can pay for with a check and one row each. Markets are remembered per series; do not put the same series in two schedules that can run at the same time.

## `resetMonitoringState` (type: `boolean`):

Clears every remembered market for this Actor, so the next monitoring run returns every market again as a first check. This affects all your monitoring runs, because markets are remembered per series rather than per list. Turn it off again after one run: left on in a schedule, every run returns every market again and charges for it.

## Actor input object example

```json
{
  "series": [
    "KXHIGHNY",
    "KXLOWTNYC",
    "KXHIGHCHI"
  ],
  "discoverSeries": false,
  "marketStatus": "open",
  "includeForecast": true,
  "maxResults": 1000,
  "monitoringMode": false,
  "resetMonitoringState": false
}
```

# Actor output Schema

## `results` (type: `string`):

One row per Kalshi weather market: series and market ticker, strike range, target date, status, yes/no bid and ask, last price, volume, open interest, close time, result and settled value, the settlement station named in the rules, and the NWS forecast high and low of that station for the market date; in monitoring mode only markets whose price, volume, open interest, status or result changed. Unknown series, empty series, refusals and limits come back as free rows that say why.

# API

You can run this Actor programmatically using our API. Below are code examples in JavaScript, Python, and CLI, as well as the OpenAPI specification and MCP server setup.

## JavaScript example

```javascript
import { ApifyClient } from 'apify-client';

// Initialize the ApifyClient with your Apify API token
// Replace the '<YOUR_API_TOKEN>' with your token
const client = new ApifyClient({
    token: '<YOUR_API_TOKEN>',
});

// Prepare Actor input
const input = {
    "series": [
        "KXHIGHNY",
        "KXLOWTNYC",
        "KXHIGHCHI"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("neverempty/kalshi-weather-markets-api").call(input);

// Fetch and print Actor results from the run's dataset (if any)
console.log('Results from dataset');
console.log(`💾 Check your data here: https://console.apify.com/storage/datasets/${run.defaultDatasetId}`);
const { items } = await client.dataset(run.defaultDatasetId).listItems();
items.forEach((item) => {
    console.dir(item);
});

// 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/js/docs

```

## Python example

```python
from apify_client import ApifyClient

# Initialize the ApifyClient with your Apify API token
# Replace '<YOUR_API_TOKEN>' with your token.
client = ApifyClient("<YOUR_API_TOKEN>")

# Prepare the Actor input
run_input = { "series": [
        "KXHIGHNY",
        "KXLOWTNYC",
        "KXHIGHCHI",
    ] }

# Run the Actor and wait for it to finish
run = client.actor("neverempty/kalshi-weather-markets-api").call(run_input=run_input)

# Fetch and print Actor results from the run's dataset (if there are any)
print(f"💾 Check your data here: https://console.apify.com/storage/datasets/{run.default_dataset_id}")
for item in client.dataset(run.default_dataset_id).iterate_items():
    print(item)

# 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/python/docs/quick-start

```

## CLI example

```bash
echo '{
  "series": [
    "KXHIGHNY",
    "KXLOWTNYC",
    "KXHIGHCHI"
  ]
}' |
apify call neverempty/kalshi-weather-markets-api --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,neverempty/kalshi-weather-markets-api"
        }
    }
}
```

The hosted server signs you in with OAuth on first connect, so no API token belongs in this config. Clients without OAuth support can send an `Authorization: Bearer <APIFY_API_TOKEN>` header instead, using a token from API & Integrations in Apify Console (https://console.apify.com/settings/integrations).

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/actors/fGcZ6vnBvzNY1yKgV/builds/Jty3gZbOFT5FWTfYJ/openapi.json
