History, Bulk and WebSocket
{user} is elon, cruz or trump. Timestamps are Unix epoch milliseconds (UTC).
History
Section titled “History”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.
Counter
Section titled “Counter”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.
Prices
Section titled “Prices”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.
Order books
Section titled “Order books”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.
Example
Section titled “Example”Page through a day of Elon counter history (Python, standard library only):
import jsonimport timeimport 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"]Bulk parquet
Section titled “Bulk parquet”Public archive
Section titled “Public archive”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}.
curl -A "my-app/1.0" https://polystrike.xyz/api/v1/bulk/publicFull archive
Section titled “Full archive”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.
WebSocket
Section titled “WebSocket”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, jsonimport 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())