How to download historical data
Walk the /rounds endpoint backwards with an `until` cursor to build a Parquet / CSV / JSONL dataset of every round in any window. This guide covers pagination, checkpointing, rate-limit handling and a working Python script that you can resume after a crash.
1. Cursor model
No opaque cursor — you page on `finalized_at` ISO timestamps. Rounds come back newest-first. To walk into older history, set `until` to the oldest finalized_at you've seen so far: each call returns the next `limit` rounds with finalized_at < until. Repeat until a page comes back empty. (The mirror param `since` does the opposite — finalized_at > since — for forward polling of live deltas.)
2. Page size
limit max is 10000. We recommend 1000 for steady throughput; very large pages on Starter tier may trip the per-minute rate limit, so pace your loop. Pro and Enterprise tiers handle large pages cleanly.
3. Checkpointing
Persist your last successful `until` to a small JSON file (or Redis key). On restart, resume from there — the API call is idempotent so re-fetching the boundary row twice is harmless.
4. Full backfill script
import json, time, requests
from pathlib import Path
API = 'https://api.trackersino.com'
KEY = 'YOUR_KEY'
SLUG = 'stake-crash' # any slug from the Games & slugs table
LIMIT = 1000
END = '2026-01-01T00:00:00Z' # stop point (oldest finalized_at to keep)
OUT = Path(f'{SLUG}.jsonl')
CKPT = Path(f'{SLUG}.ckpt')
# Resume: 'until' is the oldest finalized_at we've written so far.
until = CKPT.read_text().strip() if CKPT.exists() else None
sess = requests.Session()
sess.headers['Authorization'] = f'Bearer {KEY}'
with OUT.open('a') as f:
while True:
params = {'limit': LIMIT, 'only_finalized': 'true'}
if until:
params['until'] = until # walk into OLDER history
r = sess.get(f'{API}/v1-beta/games/{SLUG}/rounds', params=params, timeout=15)
if r.status_code == 429:
wait = int(r.headers.get('Retry-After', '5')) + 1
print(f'rate-limit · sleeping {wait}s'); time.sleep(wait); continue
r.raise_for_status()
rows = r.json() # newest-first
if not rows: break # reached the start of history
for row in rows:
f.write(json.dumps(row) + '\n')
oldest = rows[-1]['finalized_at'] # last row = oldest in this page
until = oldest # next page goes older still
CKPT.write_text(until)
if oldest <= END: break # hit our stop point
time.sleep(0.5) # be polite
print('done')5. Storage formats
For analysis: Parquet (columnar, fast aggregations). For streaming downstream: JSONL (one round per line). For SQL: ingest directly with COPY into PostgreSQL/ClickHouse. The script below writes JSONL — pipe through duckdb or polars to convert.
6. Rate-limit handling
On 429, respect Retry-After (seconds). The script below sleeps for the value the server sends + 1s of jitter, then resumes. Don't hammer — back off properly so the next request goes through cleanly.
Multi-TB dataset?
Enterprise tier offers a one-shot dump via signed S3 URLs — much faster than walking /rounds for large windows. Ask us on Telegram.
Open Telegram →