Skip to content

History, Bulk and WebSocket

{user} is elon, cruz or trump. Timestamps are Unix epoch milliseconds (UTC).

GET /api/v1/history/{user}/{counter|prices|books|tweets}, with a Data key (X-API-Key header) or an x402 payment of $0.01 per call.

Every history response has the same envelope:

{
"timestamp": 1790795280353,
"freshness": "live",
"data": [ ... ],
"next_cursor": 18234411
}

Rows come in id order. Pass next_cursor back as cursor until it is null. limit is 1-5000 (default 1000). Keep each request to 31 days or less; prices and books answer 422 to a wider range. For long windows, use the bulk files.

GET /api/v1/history/{user}/counter?from_ms=...&to_ms=...

Counter snapshots: our count, XTracker’s and the Polymarket page’s, with the deltas. Optional: cursor, limit.

GET /api/v1/history/{user}/prices?from_ms=...&to_ms=...

Bucket price snapshots with event_id, market_title, token_id, yes_price, timestamp. Optional: event_id (one event), cursor, limit. At most 31 days between from_ms and to_ms.

GET /api/v1/history/{user}/books?from_ms=...&to_ms=...

Order-book snapshots; bids and asks are lists of [price, size]. Optional: token_id (one outcome token), cursor, limit. At most 31 days between from_ms and to_ms.

GET /api/v1/history/{user}/tweets

Every post we recorded, deleted ones included, with is_counted, filter_reason, is_deleted, deleted_at and the quoted or reposted text. No required parameters. Optional: q (substring of the text), since and until (on created_at), cursor, limit. The post time is created_at here, not created_ts as in the recent-posts feeds.

Page through a day of Elon counter history (Python, standard library only):

import json
import time
import urllib.request
KEY = "ps_pro_..." # your Data key
def get(path):
req = urllib.request.Request(
"https://polystrike.xyz" + path,
headers={"User-Agent": "my-app/1.0", "X-API-Key": KEY},
)
with urllib.request.urlopen(req, timeout=15) as resp:
return json.load(resp)
now = int(time.time() * 1000)
cursor, rows = 0, []
while True:
page = get(f"/api/v1/history/elon/counter?from_ms={now - 86_400_000}&to_ms={now}"
f"&cursor={cursor}&limit=5000")
rows += page["data"]
if page["next_cursor"] is None:
break
cursor = page["next_cursor"]

GET /api/v1/bulk/public

Open: no key and no payment. Lists every public parquet file, that is, files older than 30 days, under CC BY 4.0. It holds counter snapshots and bucket-price snapshots for elon, cruz and trump. Each entry is {table, date, file, bytes}; download a file at /api/v1/bulk/public/{table}/{date}/{file}.

Terminal window
curl -A "my-app/1.0" https://polystrike.xyz/api/v1/bulk/public

GET /api/v1/bulk/{user}

Data key only. The same listing for the full archive of {user}_snapshots, {user}_market_snapshots and {user}_orderbook_snapshots, up to the present; download at /api/v1/bulk/{user}/{table}/{date}/{file}. Per-call x402 payers get 403 bulk_is_subscription_only.

wss://polystrike.xyz/ws, Data key only.

Pass the key as an X-API-Key header or as ?api_key=. Without a valid Data key the socket sends one {"type": "error", "code": "pro_required", ...} message and closes with code 1008.

Subscribe to every open window of an account, or to one window:

{"action": "subscribe", "channel": "elon:*"}
{"action": "subscribe", "channel": "elon:<event_id>"}

Several channels can be sent comma-separated. Unsubscribe with "action": "unsubscribe". Each pushed message is {"channel", "type": "snapshot", "user_id", "event_id", "data": {...counters and deltas}}. The socket relays elon, cruz and trump.

import asyncio, json
import websockets # pip install websockets
async def main():
url = "wss://polystrike.xyz/ws?api_key=ps_pro_..."
async with websockets.connect(url) as ws:
await ws.send(json.dumps({"action": "subscribe", "channel": "trump:*"}))
async for message in ws:
print(json.loads(message))
asyncio.run(main())