prizepicksapi

CSV export

Export PrizePicks projections to CSV.

The export endpoint returns the same filtered projections as JSON, one bounded CSV page at a time. Use it for spreadsheets and quick analysis; use JSON when you need every field.

Request one page

curl -sS -D - -o nba.csv \
  "https://prizepicksapi.com/api/v1/export?league=NBA&limit=200" \
  -H "Authorization: Bearer $PRIZEPICKS_API_KEY"

# Try it without a key using fictional demo rows:
curl -sS "https://prizepicksapi.com/api/v1/demo/export?league=NBA&limit=5"

The export accepts the same league, search, stat, tier, status, limit, and cursor parameters as /api/v1/projections. Response headers carry the metadata a CSV body cannot: X-Data-Mode is live or demo, X-Next-Cursor holds the next page token (empty on the last page), and live responses include X-Source-Status.

The columns, in order

ColumnSource field
id, source, is_demoIdentifiers and mode
player, team, leagueplayer.name, player.team, league
stat, period, linemarket.stat, market.period, line
more_available, more_tierselections where side = more
less_available, less_tierselections where side = less
event_starts_at, observed_at, source_updated_atTimestamps (UTC, ISO 8601)
statusactive or unavailable

Unknown values are empty cells. In a spreadsheet an empty more_available means not established, not false; keep that distinction if you add formulas. Rows are separated by CRLF and every cell is quoted.

Export every page with Python

import csv, io, os, time
from urllib.parse import urlencode
from urllib.request import Request, urlopen

KEY = os.environ["PRIZEPICKS_API_KEY"]

def export(league: str, path: str) -> None:
    cursor, wrote_header = None, False
    with open(path, "w", newline="", encoding="utf-8") as fh:
        writer = csv.writer(fh)
        while True:
            params = {"league": league, "limit": 200}
            if cursor:
                params["cursor"] = cursor
            req = Request("https://prizepicksapi.com/api/v1/export?" + urlencode(params),
                          headers={"Authorization": "Bearer " + KEY})
            with urlopen(req, timeout=30) as res:
                if res.headers.get("X-Data-Mode") != "live":
                    raise RuntimeError("Expected live data")
                status = res.headers.get("X-Source-Status")
                nxt = res.headers.get("X-Next-Cursor") or None
                rows = list(csv.reader(io.StringIO(res.read().decode("utf-8"))))
            header, body = rows[0], rows[1:]
            if not wrote_header:
                writer.writerow(header)
                wrote_header = True
            writer.writerows(body)
            print(len(body), "rows; source_status =", status)
            if not nxt:
                return
            if nxt == cursor:
                raise RuntimeError("Repeated cursor")
            cursor = nxt
            time.sleep(6.1)

export("NBA", "nba-projections.csv")

Parsing each page with the csv module and writing one header avoids the duplicated header rows and broken line endings you get from concatenating raw files. Record the printed source_status with the file: a CSV from a stale collection is a dated snapshot, not a current board.

Spreadsheet safety is built in

Text that begins with =, +, @, a tab, a carriage return, or a minus sign followed by a non-digit is prefixed with an apostrophe, so a hostile string cannot run as a formula in Excel or Google Sheets. Negative numbers are left unchanged. If you build your own CSV from JSON, apply the same rule.

Avoid keys in spreadsheet URLs

Spreadsheet import functions that fetch a URL cannot send an Authorization header, and putting a key in a query string is unsupported. Download the file from a script or your backend, then import it. The demo export needs no key if you only want to prototype a sheet layout.

Frequently asked questions

Does the export download the entire database?

No. Each response is one page of up to 200 rows. Continue with the X-Next-Cursor header; each page counts as one request.

Does the CSV include history or payout multipliers?

No. It contains current projection rows with tiers and availability per side. Use the history endpoint and the JSON selections array for those.

References

Current API documentation ↗Machine-readable OpenAPI contract ↗RFC 4180: CSV format ↗OWASP: CSV injection ↗

PrizePicks API is an independent data service. It is not affiliated with or endorsed by PrizePicks. Observations, completeness, and freshness are separate claims; consult source status before relying on a stored line.