outcome·tick

API

With a key in hand, three commands put a file on your disk. The first block below is copy-pasteable as-is.

Sixty seconds

Replace the key on line 1 with your own (shown once on the page right after payment); paste the rest as-is.

# 1. your key, from the page you saw right after paying
export OT_KEY="ck_a1b2c3d4e5f6.xxxxxxxxxxxxxxxxxxxxxxxx"

# 2. what can I get?
curl -s -H "Authorization: Bearer $OT_KEY" \
  https://outcometick.com/v1/meta

# 3. find a file, then download it
curl -s -H "Authorization: Bearer $OT_KEY" \
  "https://outcometick.com/v1/files?asset=btc&dataset=prices"

curl -L -H "Authorization: Bearer $OT_KEY" \
  "https://outcometick.com/v1/dl/2026-08-12/BTCUSD-prices-2026-08-12.csv.gz" \
  -o BTCUSD-prices-2026-08-12.csv.gz

The -L in step 3 matters: the download endpoint answers with a 302 to a short-lived object-storage URL. Files come straight from storage — they never pass through our server.

One line in Python

pandas, DuckDB and wget cannot attach a header to a URL, so the download endpoint also accepts ?api_key=. Be aware it puts the key in browser history and proxy logs — prefer the header wherever you can set one.

import pandas as pd

KEY = "ck_a1b2c3d4e5f6.xxxxxxxxxxxxxxxxxxxxxxxx"
df = pd.read_csv(
    "https://outcometick.com/v1/dl/2026-08-12/"
    "BTCUSD-prices-2026-08-12.csv.gz?api_key=" + KEY
)
print(df.head())

Common tasks

One day, one asset, one interval

Every filter is optional. Use date for a single day, or from / to for a range.

# every BTC 5-minute order book for one day
curl -s -H "Authorization: Bearer $OT_KEY" \
  "https://outcometick.com/v1/files?date=2026-08-12&asset=btc&interval=5m&dataset=book"

A month of settlement prices, verified on the way in

Each file carries a sha256 identical to the archive manifest. A match proves you have exactly what we published — not merely that the transfer succeeded.

#!/usr/bin/env bash
# a month of BTC settlement prices, downloaded and checksum-verified
set -euo pipefail
export OT_KEY="ck_a1b2c3d4e5f6.xxxxxxxxxxxxxxxxxxxxxxxx"

curl -s -H "Authorization: Bearer $OT_KEY" \
  "https://outcometick.com/v1/files?asset=btc&dataset=prices&from=2026-07-14&to=2026-08-12" \
| jq -r '.files[] | "\(.url) \(.name) \(.sha256)"' \
| while read -r url name sha; do
    curl -sL -H "Authorization: Bearer $OT_KEY" "$url" -o "$name"
    echo "$sha  $name" | sha256sum -c -
  done

Straight into one DataFrame

import pandas as pd, requests

KEY  = "ck_a1b2c3d4e5f6.xxxxxxxxxxxxxxxxxxxxxxxx"
BASE = "https://outcometick.com"
auth = {"Authorization": f"Bearer {KEY}"}

# every 1-minute kline for BTC over a week
r = requests.get(f"{BASE}/v1/files", headers=auth, params={
    "asset": "btc", "dataset": "klines", "interval": "1m",
    "from": "2026-08-06", "to": "2026-08-12",
})
files = r.json()["files"]

df = pd.concat(
    pd.read_csv(f["url"] + "?api_key=" + KEY) for f in files
).sort_values("ts_ms")
print(len(df), "rows")

The three endpoints

GET /v1/metaSee what you can get

The dimensions come back already narrowed to your tier — a Polymarket plan never sees Predict.fun. Note the venues do not cover the same assets: Polymarket 8, Predict.fun 3.

{
  "firstDay": "2026-06-06", "lastDay": "2026-08-12", "days": 68,
  "venues":    ["polymarket"],
  "assets":    ["BNB","BTC","DOGE","ETH","HYPE","SOL","XRP","ZEC"],
  "intervals": ["1s","1m","3m","5m","15m","30m","1h","2h","4h","6h","8h","12h","1d","3d","1w","1mo"],
  "datasets":  { "prices": "…", "book": "…", "klines": "…" }
}

GET /v1/filesFind files

Every file in the response carries its own url; hand it straight to your downloader.

Filters (all optional)
assetbtc / eth / … comma-separated for several, e.g. asset=btc,eth
datasetprices / twap30s / twap60s / book / price_change / last_trade_price / markets / klines
interval5m and 15m for markets; 1m, 1h, 1d … for klines
venuepolymarket / predict
datea single day — same as from=to=that day
from / toa range, at most 92 days per call. Omit both for the latest day
{
  "from": "2026-08-12", "to": "2026-08-12", "days": 1,
  "count": 1, "bytes": 1655751,
  "files": [{
    "date":     "2026-08-12",
    "name":     "BTCUSD-prices-2026-08-12.csv.gz",
    "asset":    "BTC",
    "dataset":  "prices",
    "interval": null,
    "bytes":    1655751,
    "sha256":   "a8b4f866772578e4…",
    "url":      "https://outcometick.com/v1/dl/2026-08-12/BTCUSD-prices-2026-08-12.csv.gz"
  }]
}

GET /v1/dl/:date/:nameDownload one file

Answers 302 to a short-lived object-storage URL (valid 15 minutes). Use curl -L, or any client that follows redirects.

When something goes wrong

401Wrong key, revoked key, or a lapsed subscription. Try the /v1/meta call from step 2 — if that works, the key is fine.
403 date outside…That day is outside your coverage. The floor field in the response is the earliest date you can request; Pro is the trailing 30 days.
404 file not found in your scopeEither the file does not exist for that day, or it is not part of your tier (e.g. a Polymarket plan asking for a Predict.fun file). List /v1/files for the day to see what is actually there.
files returns an empty arrayFilters too narrow or misspelled. Drop a filter, or check /v1/meta for the valid values.
429Too many requests — back off and retry.
5xxTemporary; retrying is safe.

Reading the fields

feed_ts_msEvent time: the timestamp upstream put on the report (UTC ms)
server_ts_msWhen the upstream server sent it
recv_msWhen we received it. All three are kept apart, never merged — so you can measure the capture path
valuePrice as a float, for convenience
full_accuracy_valueThe same price as a fixed-point integer string (1e18). Use this to recompute outcomes, not value
strike_valueThe price to beat for that market. Null when we cannot establish it honestly — never guessed from a nearby tick
outcome_pricesThe settlement. ["1","0"] means Up won, ["0","1"] means Down won

Two conventions you need

The settlement rule changed on 2026-08-07

Before it, the instantaneous Chainlink stream decided the outcome; after it, the TWAP streams do (30s lookback for 5-minute markets, 60s for 15-minute). Pick the rule from the market’s own raw.cryptoMarketConfig.twapEnabled rather than from the date — both kinds coexist on the same day.

Frames are stored as received

Out-of-order included; we do not reorder an archive. Sort at query time if you need chronological order. Gaps are likewise not hidden — the paid dataset ships a daily coverage report.