Guides / API Guide

ProbSights API: JavaScript Quickstart

A working Node/TypeScript client for the ProbSights API: find a market, pull its orderbook history, and page to the end correctly.

Setup

const BASE = "https://api.probsights.com/v1";

async function get(path, params = {}) {
  const qs = new URLSearchParams(
    Object.entries(params).filter(([, v]) => v !== undefined).map(([k, v]) => [k, String(v)]),
  );
  const res = await fetch(`${BASE}${path}?${qs}`, {
    headers: { Authorization: `Bearer ${process.env.PROBSIGHTS_API_KEY}` },
  });
  if (!res.ok) {
    // Errors are { message, status } — surface the message, not the status code.
    const body = await res.json().catch(() => ({}));
    throw new Error(body.message ?? `Request failed (${res.status})`);
  }
  return res.json();
}

Keep the key server-side. In a browser bundle it is readable by anyone who loads the page.

Find a market

// "q" or "series_id" is required; omitting both is a 400.
const markets = await get("/search/markets", {
  q: "bitcoin", status: "active", sort_by: "volume", limit: 5,
});
const marketId = markets[0].market_id;

Pull orderbook history, paged

// Date.parse gives MILLISECONDS; the API wants seconds.
const unix = (iso) => Math.floor(Date.parse(iso) / 1000);

async function* orderbookHistory(venue, marketId, startIso, endIso, granularity = "1m") {
  const params = {
    market_id: marketId,
    start_time: unix(startIso),
    end_time: unix(endIso),
    granularity,
    limit: 1000,
  };
  for (;;) {
    const res = await get(`/historical/${venue}/orderbook`, params);
    yield* res.snapshots;
    if (!res.pagination?.has_more) return;
    // Follow the cursor rather than advancing start_time, which would drop or
    // duplicate rows sharing a timestamp.
    params.pagination_key = res.pagination.pagination_key;
  }
}

const snapshots = [];
for await (const s of orderbookHistory(
  "polymarket", marketId, "2025-01-20T00:00:00Z", "2025-01-21T00:00:00Z",
)) {
  snapshots.push(s);
}
console.log(snapshots.length, snapshots[0]?.mid, snapshots[0]?.spread);

And the trade tape

const { trades } = await get("/historical/polymarket/trades", {
  market_id: marketId,
  start_time: unix("2025-01-20T00:00:00Z"),
  end_time: unix("2025-01-21T00:00:00Z"),
  limit: 1000,
});

Kalshi is the same shape — swap polymarket for kalshi; its snapshots expose yes_bids/no_bids instead of bids/asks.

Related

Related guides

Data from Kalshi and Polymarket. Search live API docs Pricing