# Prediction Markets Lookup: Kalshi & Polymarket API from $1/1k (`accountable_eel/prediction-markets-lookup`) Actor

Kalshi and Polymarket prediction markets in one actor. Search by keyword or fetch an exact market by ticker/id and get venue, question, live yes/no prices, volume, liquidity and close time. Reads both venues' own official public JSON APIs, no login. Billed per market returned, never per search.

- **URL**: https://apify.com/accountable\_eel/prediction-markets-lookup.md
- **Developed by:** [Adrian Voss](https://apify.com/accountable_eel) (community)
- **Categories:** Business, Developer tools
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $0.50 / 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?

Actors are web data automations that power AI and operations. They run on the Apify platform to scrape websites, process data, connect APIs, and automate workflows.
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.
Actors are written with capital "A".

## 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.
The best way to integrate Actors is as follows.

- **AI agents and MCP clients** — the [Apify MCP server](https://docs.apify.com/integrations/mcp.md) at `https://mcp.apify.com` (remote, streamable HTTP, OAuth on first use).
- **Agentic workflows and local Actor development** — [Agent Skills](https://apify.com/.well-known/agent-skills/index.json) with the [Apify CLI](https://docs.apify.com/cli/docs.md): `npm install -g apify-cli`, then `apify login`.
- **JavaScript/TypeScript projects** — the official [JS/TS client](https://docs.apify.com/api/client/js/docs.md): `npm install apify-client`.
- **Python projects** — the official [Python client](https://docs.apify.com/api/client/python/docs.md): `pip install apify-client`.
- **Any other language** — the [REST API](https://docs.apify.com/api/v2.md).

For usage examples, see the [API](#api) section below.

For more details, see Apify documentation as [Markdown index](https://docs.apify.com/llms.txt) and [Markdown full-text](https://docs.apify.com/llms-full.txt).

# README

## Prediction Markets Lookup: Kalshi & Polymarket API

Search Kalshi and Polymarket by keyword, or fetch an exact market by ticker or id, and get one
row per market: venue, question, live yes/no price, volume, liquidity and close time. Reads
each venue's own official public JSON API directly — no login, no API key, no scraping.

### Who it's for

Built for anyone who wants prediction-market data without hand-rolling two separate API
integrations. Traders and researchers pull live yes/no pricing on a topic across both venues in
one call instead of comparing tabs. News and content teams check what a market is currently
pricing on an election, a rate decision, or a sports outcome before publishing. Builders
wiring prediction-market odds into a dashboard, a bot, or an AI agent get one flat schema
instead of learning Kalshi's `trade-api` and Polymarket's `gamma-api` separately.

### Why this one

- **Two official venues, one actor.** Kalshi's `trade-api/v2` and Polymarket's `gamma-api` are
  both public and unauthenticated — no scraping, no headless browser, no CSS selectors to break.
- **Keyword or exact id, auto-detected.** Type a topic like `fed rate` to search, or paste a
  Kalshi ticker or Polymarket market id/slug to fetch that one market directly — same input
  field, no mode switch needed.
- **Billed per market returned, not per search.** A keyword that matches 12 markets costs 12; a
  keyword that matches nothing costs nothing. An exact ticker/id lookup that resolves costs one.
- **One flat row per market.** `yesPrice`, `noPrice`, `volume`, `liquidity` and `closeTime` are
  named the same way regardless of which venue a market came from.
- **`venues` and `status` narrow every search** to one venue or both, and to open or closed
  markets, without changing the query itself.

### What you get

One row per market matched, for every query submitted.

| Field | Type / format | Description |
|---|---|---|
| `query` | text | The keyword or ticker/id exactly as submitted. |
| `found` | boolean | Whether at least one market matched. Gates billing — `false` rows are never charged. |
| `venue` | text | `kalshi` or `polymarket`. |
| `marketId` | text | The venue's own identifier — a Kalshi ticker or a Polymarket market id. |
| `question` | text | The market's question/title, e.g. "Will the Fed cut rates in September?". |
| `yesPrice` | number | Current price of the "Yes" side, 0-1 (a probability-like price, not a percentage). |
| `noPrice` | number | Current price of the "No" side, 0-1. |
| `volume` | number | Total traded volume the venue reports for this market. |
| `liquidity` | number | Resting liquidity the venue reports for this market. |
| `closeTime` | date (ISO 8601) | When the market closes/expires. |
| `url` | link | Direct market page, when the venue exposes one (Polymarket only — see FAQ). |
| `scrapedAt` | date (ISO 8601) | When the lookup ran. |

### Keyword search vs exact lookup

The same `queries` field accepts two different input shapes, detected automatically per line.

**Exact ticker/id** — a Kalshi ticker (all-caps, dash-separated, e.g.
`KXNFLREC-26SEP14DENKC-KCNGRAY83-5`) or a Polymarket market id/condition id/slug — fetches that
one market directly from the venue it belongs to, regardless of `venues`. One row, billed once.

**Keyword** — anything else is treated as free text. It's matched against every open (or, per
`status`, closed) market's question/title on the selected venue(s), case-insensitive substring
match, up to `maxMarketsPerQuery` results. This is real, but it's not a ranked search: neither
Kalshi's nor Polymarket's public listing endpoint exposes full-text search, so this actor fetches
one page of markets per venue and filters it client-side. A very specific or unusual keyword may
turn up nothing even if a matching market exists further back in that venue's full catalogue —
if you know the exact ticker/id, use it instead for a guaranteed hit.

### Price

- **Market returned**: $1 per 1,000 markets

Plus a $0.00005 start fee per run. Each event above is billed independently, only when it actually returns data — misses (`found:false`) are never charged.

Intended pricing: **$1 per 1,000 markets returned** (event `market-found`), plus a $0.00005
actor-start fee per run. You're billed per market row actually returned, not per search — a
keyword that matches nothing costs nothing beyond the start fee, and `maxMarketsPerQuery` is
your budget dial on a broad keyword. (Live PAY\_PER\_EVENT pricing is applied by the portfolio's
pricing pipeline after publish — the block above updates automatically once that runs.)

### How to use

1. **In the Apify Console.** Open the actor page and click **Start** — the `queries` field is already pre-filled with a working example. Results land in the run's dataset as soon as each item is found.
2. **Via the API.** Call it directly with a POST request — no Console needed once you have an API token:
   ```bash
   curl "https://api.apify.com/v2/acts/accountable_eel~prediction-markets-lookup/run-sync-get-dataset-items?token=<YOUR_TOKEN>" \
     -X POST \
     -H "Content-Type: application/json" \
     -d '{"queries":["election"]}'
   ```
3. **On a schedule.** Save this actor as an Apify **Task** with the input you want, then add a **Schedule** (hourly, daily, weekly) so it runs on its own — no server of your own required.

1) Paste keywords or exact tickers/ids into `queries` — one per line, mixed freely.
2) Set `venues` (both, Kalshi only, or Polymarket only) and `status` (open, closed, or any) to
   narrow keyword search. Both are ignored for an exact ticker/id, which always resolves to its
   own venue and current status.
3) Set `maxMarketsPerQuery` to cap how many markets one broad keyword can return — and cost.
4) Read the dataset. Each matched market is its own row; a query with no match returns
   `found: false` and is never charged.

**Common ways teams use this:**

- **Check the market's current price on a topic** before writing about it or trading on it.
- **Compare the same event across both venues** by leaving `venues` on "both".
- **Track a specific market's price over time** by re-running its exact ticker/id on a schedule.
- **Feed live prediction-market odds into a dashboard, bot, or AI agent** with one flat schema.
- **Scan for markets on a theme** (e.g. "fed", "election", "recession") across open markets.

### Input

```json
{
  "queries": [
    "election"
  ]
}
```

One per line. A free-text keyword (e.g. "fed rate") searches open markets on the selected venue(s) and returns every match. An exact Kalshi ticker (e.g. "KXNFLREC-26SEP14DENKC-KCNGRAY83-5") or Polymarket market id/slug fetches that one market directly. Accepted formats: fed rate decision, KXNFLREC-26SEP14DENKC-KCNGRAY83-5, will-the-fed-cut-rates-in-2026.

```json
{
  "queries": ["fed rate", "election", "KXNFLREC-26SEP14DENKC-KCNGRAY83-5"],
  "venues": "both",
  "status": "open",
  "maxMarketsPerQuery": 20
}
```

`queries` mixes keywords and exact tickers/ids freely. `venues` is `both` (default), `kalshi`, or
`polymarket` — only affects keyword search, since an exact ticker/id always resolves to its own
venue. `status` is `open` (default), `closed`, or `any` — also keyword-search only. `maxMarketsPerQuery`
(default 20) caps and bills how many markets one keyword can return.

### Sample output

One row per market matched:

| query | found | status | marketCount | markets | venue | marketId | question | yesPrice | noPrice | volume | liquidity | closeTime | url | scrapedAt |
| --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- |
| election | true | OK | 20 | \<all markets found (full list)> | polymarket | 561229 | Will JD Vance win the 2028 US Presidential Election? | 0.2455 | 0.7545 | 16219868.429494996 | 429187.3432 | 2028-11-07T00:00:00Z | https://polymarket.com/event/will-jd-vance-win-the-2028-us-presidential-election | 2026-09-08T17:38:24.405Z |

A single row in full:

```json
{
  "query": "KXNFLREC-26SEP14DENKC-KCNGRAY83-5",
  "found": true,
  "status": "OK",
  "venue": "kalshi",
  "marketId": "KXNFLREC-26SEP14DENKC-KCNGRAY83-5",
  "question": "Noah Gray: 5+ receptions",
  "yesPrice": 0.43,
  "noPrice": 0.57,
  "volume": 1280,
  "liquidity": 340.5,
  "closeTime": "2026-09-17T00:15:00Z",
  "url": null,
  "scrapedAt": "2026-09-08T01:00:00.000Z"
}
```

A query that matches nothing still returns a row, and is never charged:

```json
{
  "query": "some very specific phrase nobody made a market on",
  "found": false,
  "status": "NOT_FOUND",
  "scrapedAt": "2026-09-08T01:00:00.000Z"
}
```

### Use it from Clay, n8n, Make, or an AI agent

This actor runs synchronously over plain HTTP — call it directly from a script, a workflow tool, or an AI agent, no Apify Console needed once you have an API token.

```bash
curl "https://api.apify.com/v2/acts/accountable_eel~prediction-markets-lookup/run-sync-get-dataset-items?token=<YOUR_TOKEN>" \
  -X POST \
  -H "Content-Type: application/json" \
  -d '{"queries":["election"]}'
```

**n8n.** Add an HTTP Request node: Method `POST`, URL `https://api.apify.com/v2/acts/accountable_eel~prediction-markets-lookup/run-sync-get-dataset-items?token=<YOUR_TOKEN>`, Body Content Type `JSON`, JSON Body `{"queries":["election"]}` (swap in an expression from an earlier node for a real value).

**Clay.** Add an "HTTP API" column: Method `POST`, URL `https://api.apify.com/v2/acts/accountable_eel~prediction-markets-lookup/run-sync-get-dataset-items?token=<YOUR_TOKEN>`, Body `{"queries":["{{search}}"]}`, mapping the row's search into the `queries` array.

**MCP.** In Claude, Cursor, or any MCP client with the Apify MCP server, ask for "Prediction Markets Lookup | Apify" — the agent will find and run this actor.

### Tips

- **Use the exact ticker/id when you have it.** It's a guaranteed hit and a single billed row,
  where a keyword is a best-effort substring match over one page of results.
- **`maxMarketsPerQuery` is your cost control on broad keywords.** Set it low (5-10) for a quick
  scan of a topic instead of the default 20 if you're running many keywords.
- **`yesPrice` and `noPrice` are prices, not always-summing-to-1 probabilities.** Prediction
  markets can carry a spread; treat the gap between the two as the market's current spread, not
  an error.
- **Narrow `status` to `closed` to check how a market actually resolved**, rather than its
  live price while still open.
- **A keyword that returns nothing doesn't mean no such market exists** — it means none matched
  in the first page this actor reads. Try the venue's own site to search more broadly, then
  come back with the exact ticker/id.

### vs. alternatives

| | What it costs | What you get | Trade-off |
|---|---|---|---|
| **This actor** (`prediction-markets-lookup`) | $1 per 1,000 markets returned, $0.00005 actor start, nothing for a query with no match | Kalshi and Polymarket in one actor, one flat schema, keyword search or exact lookup | Keyword search is a single-page substring match, not a ranked full-text search — see "Keyword search vs exact lookup". |
| **bigdavidson/kalshi-weather-markets** | See its own page | Kalshi-only, weather-market-focused | Single-venue and single-category; ~95% of its runs fail per the Apify Store's own run-failure stat, an incumbent this niche's weakness was measured against, not a benchmark to match. |
| **Doing it yourself** | Your time + learning two separate API shapes, decimal-vs-string price fields, and building your own keyword filter | The same data | This actor absorbs both venues' quirks (Kalshi's dollar-string prices, Polymarket's JSON-encoded-string outcome arrays) and hands back one flat table. |

### FAQ

**Do I need a Kalshi or Polymarket account?**
No. Both venues' market-listing data is public. This actor only reads public endpoints — it
never places a trade and never needs your credentials.

**Why is `url` empty for Kalshi markets?**
Kalshi's API doesn't return a canonical web-page slug for a market — its site builds one from
the title client-side, which this actor can't reproduce reliably without guessing wrong. Rather
than fabricate a link that might 404, `url` is left `null` for Kalshi. Polymarket's API does
return a real slug, so Polymarket rows carry a working `url`.

**What does "found" mean for a keyword query?**
At least one market's question/title contained the keyword (case-insensitive) on the venue(s)
and status you selected. Zero matches returns `found: false` and is never charged.

**Can I get every market on a topic, not just the first page?**
Not in this version. Keyword search reads one page (up to a few hundred markets) per venue per
query — see "Keyword search vs exact lookup". An exact ticker/id lookup is unaffected and always
resolves directly.

**Are `yesPrice`/`noPrice` percentages?**
They're prices on a 0-1 scale that the market treats as an implied probability, but they're not
guaranteed to sum to exactly 1 — a live market can carry a bid/ask spread.

**Can an AI agent run this on its own?**
Yes. It's registered with the Apify MCP server, so a Claude or Cursor agent with that MCP
connected can find "Prediction Markets Lookup" and pull dataset rows back without any
integration code.

### Related actors

- [Google Ads Presence Lookup](https://apify.com/accountable_eel/google-ads-presence-lookup) —
  another official-API lookup actor in this portfolio's data-intelligence lane.
- [Tech Stack Lookup](https://apify.com/accountable_eel/tech-stack-lookup) — this portfolio's
  reference actor for README structure and pricing conventions.

# Actor input Schema

## `queries` (type: `array`):

One per line. A free-text keyword (e.g. "fed rate") searches open markets on the selected venue(s) and returns every match. An exact Kalshi ticker (e.g. "KXNFLREC-26SEP14DENKC-KCNGRAY83-5") or Polymarket market id/slug fetches that one market directly. Accepted formats: fed rate decision, KXNFLREC-26SEP14DENKC-KCNGRAY83-5, will-the-fed-cut-rates-in-2026. You're only charged for the ones we actually find — a miss costs nothing.

## `testRun` (type: `boolean`):

Turn this on to test your input on a small sample before running the full list. Turn it off to process everything.

## `onlyFound` (type: `boolean`):

Only keep rows where something was actually found. Misses are always free, whether or not you show them here.

## `includeKeywords` (type: `array`):

Optional. Only keep results that mention at least one of these words (e.g. a job title, a city, a product name). Leave empty to keep everything.

## `excludeKeywords` (type: `array`):

Optional. Drop any result that mentions one of these words. Leave empty to skip nothing.

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

Optional. Stop the run once this many results have been found — useful for a quick, cheap sample. Leave blank for no limit.

## `venues` (type: `string`):

Which venue(s) to query. An exact ticker/id input only ever resolves against the venue it actually belongs to.

## `status` (type: `string`):

Restricts keyword search to markets in this state. Ignored for an exact ticker/id lookup, which always returns that market regardless of status.

## `maxMarketsPerQuery` (type: `integer`):

Caps how many matching markets a single keyword query can return. You pay per market returned, so this is also your budget control. Ignored for an exact ticker/id lookup (always 1).

## `columns` (type: `array`):

Choose which pieces of information to include in each result row. All are included by default.

## `expandRows` (type: `boolean`):

When on, each market found gets its own row instead of being grouped under its search. You're still only charged once per search, no matter how many rows it produces.

## `maxConcurrency` (type: `integer`):

Parallel requests. Keep conservative — this target has no browser fallback, so getting blocked costs more than slow-and-steady.

## `proxyConfiguration` (type: `object`):

Apify Proxy config. Residential recommended for anti-bot-sensitive targets.

## Actor input object example

```json
{
  "queries": [
    "election"
  ],
  "testRun": false,
  "onlyFound": false,
  "includeKeywords": [],
  "excludeKeywords": [],
  "venues": "both",
  "status": "open",
  "maxMarketsPerQuery": 20,
  "columns": [
    "marketCount",
    "markets",
    "venue",
    "marketId",
    "question",
    "yesPrice",
    "noPrice",
    "volume",
    "liquidity",
    "closeTime",
    "url"
  ],
  "expandRows": true,
  "maxConcurrency": 5,
  "proxyConfiguration": {
    "useApifyProxy": true
  }
}
```

# Actor output Schema

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

No description

# 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 = {
    "queries": [
        "election"
    ],
    "includeKeywords": [],
    "excludeKeywords": []
};

// Run the Actor and wait for it to finish
const run = await client.actor("accountable_eel/prediction-markets-lookup").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 = {
    "queries": ["election"],
    "includeKeywords": [],
    "excludeKeywords": [],
}

# Run the Actor and wait for it to finish
run = client.actor("accountable_eel/prediction-markets-lookup").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 '{
  "queries": [
    "election"
  ],
  "includeKeywords": [],
  "excludeKeywords": []
}' |
apify call accountable_eel/prediction-markets-lookup --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,accountable_eel/prediction-markets-lookup"
        }
    }
}
```

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/00gT9YXFvwUP6NVM8/builds/OGInZVhornlvB112i/openapi.json
