Guides / API Guide

ProbSights API: Python Quickstart

A working Python client for the ProbSights API: find a market, pull its orderbook history, and page to the end without losing rows.

Setup

import os, requests
from datetime import datetime, timezone

BASE = "https://api.probsights.com/v1"
session = requests.Session()
session.headers["Authorization"] = f"Bearer {os.environ['PROBSIGHTS_API_KEY']}"

def get(path, **params):
    res = session.get(f"{BASE}{path}", params=params)
    if not res.ok:
        # Errors are {"message": "...", "status": 400} — the message names the real problem.
        raise RuntimeError(res.json().get("message", res.text))
    return res.json()

Find a market

# "q" or "series_id" is required; omitting both is a 400.
markets = get("/search/markets", q="bitcoin", status="active", sort_by="volume", limit=5)
for m in markets:
    print(m["market_id"], m["exchange"], m["question"], m.get("volume"))

market_id = markets[0]["market_id"]

Pull orderbook history, paged

def unix(y, mo, d):
    return int(datetime(y, mo, d, tzinfo=timezone.utc).timestamp())

def orderbook_history(venue, market_id, start, end, granularity="1m"):
    params = {
        "market_id": market_id,
        "start_time": start,      # Unix SECONDS, not ms, not ISO
        "end_time": end,
        "granularity": granularity,
        "limit": 1000,
    }
    while True:
        res = get(f"/historical/{venue}/orderbook", **params)
        yield from res["snapshots"]
        page = res["pagination"]
        if not page.get("has_more"):
            return
        # Follow the cursor. Advancing start_time instead drops or duplicates rows
        # that share a timestamp.
        params["pagination_key"] = page["pagination_key"]

snapshots = list(
    orderbook_history("polymarket", market_id, unix(2025, 1, 20), unix(2025, 1, 21))
)
print(len(snapshots), "snapshots")
print(snapshots[0]["mid"], snapshots[0]["spread"])

And the trade tape

trades = get("/historical/polymarket/trades",
             market_id=market_id, start_time=unix(2025, 1, 20),
             end_time=unix(2025, 1, 21), limit=1000)["trades"]
for t in trades[:5]:
    print(t["timestamp"], t["price"], t["size"], t.get("side"))

Pair the two on timestamp to check whether a simulated fill is supported by what actually traded. Kalshi works identically — swap polymarket for kalshi; its snapshots use yes_bids/no_bids and its trades use taker_side and trade_id.

Related

Related guides

Data from Kalshi and Polymarket. Search live API docs Pricing