# PM Settlements & Terms API — Kalshi + Nadex (`weighty_suona/pm-settlement-api`) Actor

- **URL**: https://apify.com/weighty_suona/pm-settlement-api.md
- **Developed by:** [Andrew Goodrich](https://apify.com/weighty_suona) (community)
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $5.00 / 1,000 settlement row (per row)s

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.

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

## Prediction Market Settlements & Terms API — Kalshi + Nadex Ground Truth

**Know what your prediction-market contract ACTUALLY settles on before you trade it.**

Every other prediction-market actor on the Apify Store sells you *prices*. This one sells **ground truth**: official settlement values, contract settlement rules, and a venue-aware settlement-reference classifier that tells you whether hedging a binary with options is a clean pair or a basis trade that can lose **both legs**.

### Why this exists

Prediction markets with near-identical titles settle on *different underlyings*:

| Market | Looks like | Actually settles on |
|---|---|---|
| Kalshi KXINXU "S\&P 500 above X at 4pm" | SPX | **SPX cash index** (close auction) ✅ hedgeable with SPX options |
| Coinbase Predict "S\&P 500 above X" | SPX | **ES futures** on most listings ⚠️ |
| Nadex "US 500 >7707 (4:15PM)" | SPX | **ES futures** ⚠️ |
| Crypto.com Predict S\&P | SPX | **ES futures at 4:15pm** (15 min after cash close) ⚠️ |
| Robinhood event contracts S\&P | SPX | **ES futures** ⚠️ |

Pairing a futures-settled binary with cash-settled options is a **basis trade, not an arb** — when cash < strike < futures, you lose both legs. Real traders have lost real money this way. This actor is the pre-trade check.

### Modes

#### 1. `classify` — settlement-reference check (the killer feature)

Input any market title/slug + venue → settlement reference, detail, and hedging verdict.

```json
{ "mode": "classify",
  "items": [
    {"venue": "coinbase", "title": "S&P 500 or above 7,700 at 4pm ET"},
    {"venue": "kalshi",   "title": "KXINXU-26SEP30H1600 S&P 500 above/below"}
  ] }
```

→ `CHECK_SLUG — MUST verify slug before pairing with options` / `SPX_CASH — CLEAN pair with SPX/XSP cash-settled options`

Covers: Kalshi, Coinbase Predict, Nadex, Crypto.com, Robinhood, generic S\&P/Nasdaq fallbacks.

#### 2. `terms` — Kalshi contract terms (live, keyless)

```json
{ "mode": "terms", "tickers": ["KXINXU-26SEP29H1600-T7869.9999"] }
```

Returns: full `rules_primary` settlement text, `result`, `close_time`, **`expiration_value` (the actual settlement print)**, `custom_strike`, plus settlement-ref classification.

#### 3. `settlements` — settled outcomes

- **Kalshi** (live API): settled markets in a date window, with results and settlement values.
  `{ "mode": "settlements", "venue": "kalshi", "series": "KXINXU", "date_from": "2026-09-01", "date_to": "2026-09-30" }`
- **Nadex** (official daily Trading Results PDFs, parsed & cached): every contract's expiration time + expiration value + winner side, pre-classified by product (US 500→ES futures, US TECH 100→NQ, CRUDE→CL, GOLD→GC...).
  `{ "mode": "settlements", "venue": "nadex", "dates": ["20260929"] }`

#### 4. `refresh_cache` — keep Nadex data current

Parses the last N days of official Nadex PDFs into the actor KV store. Run this on an Apify Schedule (daily, 22:00 UTC).

### Pricing (pay-per-event)

- `terms` lookup: **$0.01/market**
- `settlements` row: **$0.005/row**
- `classify` run: **$0.01/run** (up to 200 items)
- `refresh_cache`: free (internal)

### Data provenance & legality

- Kalshi: public keyless trade API (GET only) + each market's own `rules_primary` text.
- Nadex: official daily Trading Results PDFs published by the exchange at a public S3 bucket — the exchange's own settlement record.
- This actor **does not** resell live order books or any venue's proprietary market data; it redistributes published settlement records and contract terms.

### Use cases

- Pre-trade settlement check for prediction-market/options arb
- Backtest ground truth: score your PM signals against actual settlements
- Build venue settlement-reference tables without getting burned
- Academic research on prediction-market settlement mechanics

# Actor input Schema

## `mode` (type: `string`):

terms=Kalshi contract rules/settlement ref; settlements=settled outcomes (kalshi live, nadex cached); classify=venue-agnostic settlement-reference check; refresh_cache=internal (re-parse new Nadex PDFs)

## `venue` (type: `string`):

For settlements: kalshi or nadex. For classify: kalshi | coinbase | nadex | crypto.com | robinhood | any string

## `title` (type: `string`):

Market title or slug to classify, e.g. 'S\&P 500 or above 7,700 at 4pm ET' or 'KXINXU-26SEP30H1600'

## `items` (type: `string`):

JSON array: \[{"venue": "coinbase", "title": "S\&P 500 or above 7700 at 4pm"}, ...] — up to 200 items per run

## `ticker` (type: `string`):

Single Kalshi market ticker, e.g. KXINXU-26SEP29H1600-T7869.9999

## `tickers` (type: `array`):

Up to 100 Kalshi market tickers to fetch terms for

## `series` (type: `string`):

Series ticker for terms/settlements, e.g. KXINXU

## `date_from` (type: `string`):

Start date YYYY-MM-DD (Kalshi settlements mode)

## `date_to` (type: `string`):

End date YYYY-MM-DD (Kalshi settlements mode)

## `dates` (type: `array`):

Nadex business dates YYYYMMDD; defaults to the last 7 cached days

## `limit` (type: `integer`):

Maximum rows returned (Kalshi terms/settlements)

## `days_back` (type: `integer`):

refresh_cache mode: how many days of Nadex Trading Results PDFs to download and parse

## Actor input object example

```json
{
  "mode": "classify",
  "limit": 1000,
  "days_back": 7
}
```

# Actor output Schema

## `venue` (type: `string`):

Market venue: 'kalshi' or 'nadex'; echoed input value for classify mode. (null when not applicable).

## `ticker` (type: `string`):

Full Kalshi market ticker (terms/settlements modes); null for Nadex rows and classify mode. (null when not applicable).

## `series` (type: `string`):

Series portion of the ticker (text before the first '-'); null for Nadex/classify rows. (null when not applicable).

## `title` (type: `string`):

Human-readable market title (Kalshi rows) or the exact title you passed to classify mode; null for Nadex rows. (null when not applicable).

## `yes_sub_title` (type: `string`):

Kalshi's yes-contract subtitle clarifying the exact strike/threshold; null when absent. (null when not applicable).

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

Kalshi market status, e.g. 'settled', 'active', 'finalized'; null for Nadex/classify rows. (null when not applicable).

## `result` (type: `string`):

Kalshi final result of the market (e.g. 'yes'/'no') once settled; null otherwise. (null when not applicable).

## `close_time` (type: `string`):

Kalshi market close time as returned by the exchange API (RFC 3339); null for Nadex/classify rows. (null when not applicable).

## `expiration_time` (type: `string`):

Nadex official expiration timestamp (MM/DD/YYYY HH:MM AM/PM ET) from the trading-results PDF; null for Kalshi/classify rows. (null when not applicable).

## `expiration_value` (type: `string`):

The official settlement print: Kalshi expiration_value (e.g. '7869.42') or Nadex expiration_value from the results PDF (e.g. '92.182'); null when not yet settled. (null when not applicable).

## `settlement_rules` (type: `string`):

Kalshi's official rules_primary text for the contract; null for Nadex/classify rows. (null when not applicable).

## `custom_strike` (type: `string`):

Kalshi custom strike value when the market defines one; null otherwise. (null when not applicable).

## `settlement_ref` (type: `string`):

Venue-aware classification of what the contract actually settles on: SPX_CASH (clean option hedge) vs ES_FUTURES / NQ_FUTURES / CL_FUTURES etc. (basis risk vs cash options), FX_SPOT_REF, CRYPTO_REF_NADEX, SPORTS_RESULT, OPTIONS_COMBO, or UNKNOWN when no rule matched — treat UNKNOWN as manual-verification-required. (null when not applicable).

## `settlement_detail` (type: `string`):

Plain-English explanation of the settlement reference, e.g. 'E-mini S\&P 500 (ES) futures settlement at stated time'. (null when not applicable).

## `hedging_note` (type: `string`):

Actionable note: 'clean pair' with which options, 'BASIS RISK vs cash options', or 'DO NOT pair with options' for UNKNOWN. (null when not applicable).

## `pattern_matched` (type: `string`):

The title-pattern rule that produced the verdict in classify mode; null elsewhere. Auditable trail for every classification. (null when not applicable).

## `product` (type: `string`):

Nadex product name from the results PDF (e.g. 'US 500', 'CRUDE OIL'); null for Kalshi rows. (null when not applicable).

## `contract` (type: `string`):

Full Nadex contract display name (e.g. 'Crude Oil (Nov) >88.66 (2:30PM)'); null for Kalshi rows. (null when not applicable).

## `business_date` (type: `string`):

Nadex business date as printed (DD-Mon-YY); null for Kalshi rows. (null when not applicable).

## `date` (type: `string`):

Nadex trading-results PDF date (YYYYMMDD) the row was parsed from; null for Kalshi rows. (null when not applicable).

## `buyer` (type: `string`):

Nadex official buyer-side expiration value ('1' or '0'). (null when not applicable).

## `seller` (type: `string`):

Nadex official seller-side expiration value ('1' or '0'). (null when not applicable).

## `error` (type: `string`):

Present only on error rows: invalid input, unknown ticker, empty Nadex cache, unsupported venue, or unknown mode. Never present on successful rows. (null when not applicable).

## `mode` (type: `string`):

Literal 'refresh_cache' on cache-refresh summary rows; null on all data rows. (null when not applicable).

## `pdfs_added` (type: `string`):

refresh_cache rows only: number of new Nadex results PDFs parsed into the cache. (null when not applicable). Represented as a string.

## `days_cached` (type: `string`):

refresh_cache rows only: total number of days now held in the Nadex cache. (null when not applicable). Represented as a string.

## `updated_utc` (type: `string`):

refresh_cache rows only: ISO-8601 UTC time of the cache refresh. (null when not applicable).

## `datasetItems` (type: `string`):

All rows produced by this run (mode-dependent: settlement rows, terms rows, classification verdicts, or run summary).

## `venue_matched` (type: `string`):

The venue-pattern rule that matched in classify mode (auditable trail for the verdict); null on other modes.

# 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 = {};

// Run the Actor and wait for it to finish
const run = await client.actor("weighty_suona/pm-settlement-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 = {}

# Run the Actor and wait for it to finish
run = client.actor("weighty_suona/pm-settlement-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 '{}' |
apify call weighty_suona/pm-settlement-api --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,weighty_suona/pm-settlement-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/FYPqBrZERto8vpJbM/builds/2auJOb3jOuFpL8yN1/openapi.json
