DEV Community

Mr Zack
Mr Zack

Posted on

Kalshi's API is flooded with 8,000+ zero-volume parlay markets. If your scraper reads /markets, it's been empty since Sept 4.

Yesterday one of my Apify Actors — a cross-platform "biggest movers" feed for Polymarket and Kalshi — ran, succeeded, and delivered 100 rows. Every single row was Polymarket. The Kalshi half of the product had silently gone to zero, and nothing in the run status said so.

Here's what happened, how I caught it, and the one query parameter that fixes it.

What changed on Kalshi

GET https://api.elections.kalshi.com/trade-api/v2/markets?status=open&limit=1000 used to return a sensible mix of open markets. Since September 4, 2026 the first pages look like this:

page 1: 1000 markets, 1000 multivariate, 0 with 24h volume
page 2: 1000 markets, 1000 multivariate, 0 with 24h volume
...
page 8: 1000 markets, 1000 multivariate, 0 with 24h volume
Enter fullscreen mode Exit fullscreen mode

8,000 markets in a row, all with a ticker like KXMVECROSSCATEGORY-SHARD1-S2026…-FE61…, a mve_collection_ticker field, a 26-leg mve_selected_legs array (26 college-football moneylines chained together), volume_24h_fp: "0.00" and last_price_dollars: "0.0000". They are auto-generated multivariate ("parlay") combinations. They're valid markets, they're just not something anyone is trading, and there are thousands of them created every day.

My Actor's Kalshi loop scanned "up to 4× the requested market count" — 800 markets — and stopped. All 800 were parlay shards. Zero Kalshi rows. The Polymarket leg still worked, so the dataset was non-empty, so the run was SUCCEEDED. This is the failure mode I'm most afraid of: success-rate stays 100% while the output quietly loses half its value.

How I caught it

Not from the run status. I run a free local canary for every Actor before I look at the cloud: the production parser hit the live source from my own machine, with gates on counts and field coverage, not just exit codes. Yesterday's gate for this Actor:

PASS polymarket >=150 markets 200
FAIL kalshi >=50 markets w/ 24h vol 0 of 4000 scanned
PASS default filters -> 100 rows 100
FAIL both platforms in top 100 {"polymarket":100}
Enter fullscreen mode Exit fullscreen mode

Two red lines. If I had only checked "did it succeed / did it return 100 rows", I'd have seen nothing.

The fix: mve_filter=exclude

Kalshi's API has an (under-documented) filter for exactly this:

GET /trade-api/v2/markets?status=open&limit=1000&mve_filter=exclude
Enter fullscreen mode Exit fullscreen mode

With it, page 1 goes from 0 to 45 markets with 24-hour volume, and by page 4 you have ~600 real, actively traded markets. Ten pages (10k markets) give 2,588 open Kalshi markets with non-zero 24h volume — that's the real universe.

I also made two defensive changes so this can't recur silently:

  1. Skip anything with mve_collection_ticker or mve_selected_legs in the normalizer, regardless of what the API returns.
  2. Paginate by "useful markets collected", not "raw markets scanned" — keep pulling pages (cap 10) until I have at least 2× the requested top-N with volume > 0.

After the fix, the same default run returns 51 Polymarket + 49 Kalshi movers in the top 100, and the Kalshi log line says 618 markets with 24h volume fetched instead of nothing.

Note the /events?with_nested_markets=true endpoint is not flooded (0 MVE events on page 1), so if you're already on events you're fine. It's specifically /markets.

If you scrape Kalshi, check your last few days

Any pipeline built on /markets?status=open that either (a) stops after N pages or (b) filters on volume_24h > 0 after fetching, has most likely been returning a near-empty Kalshi set since Sept 4. Symptoms: dashboards with only Polymarket, arbitrage scanners with zero Kalshi pairs, "market count" charts falling off a cliff. Add mve_filter=exclude and re-run.

The Actor

The fixed feed is live: Prediction Market Movers | Polymarket & Kalshi Catalyst Feed — one ranked list of the biggest 24h odds swings, volume spikes and closing-soon markets across both platforms, each with a 0–100 catalyst score and signals like BIG_SWING, VOLUME_SPIKE, CLOSING_SOON, FAST_MOVER_1H. HTTP-only, public APIs, no keys; you pay per ranked row (~$0.01), and a default run costs about a cent. It also works as an MCP tool if you want an agent to ask "what moved on prediction markets today?"

Sibling Actors if you want the rest of the stack: Polymarket ↔ Kalshi Arbitrage Scanner, Polymarket Top Traders, Kalshi Weather Markets.

If this saved you a debugging session, a ⭐ or bookmark on the Actor page helps a lot — and if you've seen other Kalshi API changes this week, tell me in the comments so I can add gates for them.

Top comments (0)