Where each one fits

JobUseWhy
Consensus or fair price across many booksBroad odds APIThis API reads one board and matched quotes from three venues.
Goblin and demon tier on each sideThis APISelections carry a tier per side, in one schema.
PrizePicks line moves since 28 October 2026This APIChange-only history, as-of boards and a change feed.
Labeled outcomes on PrizePicks linesThis APIClosing-line grades where meta.leagues_graded lists the league.
Other sports, futures, limits or deep linksBroad odds APINot offered here.
A quick check against one sportsbook in NBA, NFL or NHLThis API alone/api/v1/compare already joins BetRivers, Kalshi and Polymarket where it can.

There is no shared identifier

Nothing connects a pp_ projection ID to another provider's fixture or player ID. Our sp_ and se_ stats IDs are opaque and meant only for joining our own endpoints. You are matching on names and times, so treat every join as an inference.

  1. League. Map codes explicitly. NBA and NBA1Q are different boards here.
  2. Event start. Compare event.starts_at to the feed's start time inside a small window. The example uses 15 minutes.
  3. Player name. Normalize case, accents, punctuation and suffixes. Do not expand initials or guess nicknames. Keep a reviewed alias table for the misses you care about.
  4. Stat and period. Map market names from your provider's market list, by hand, once. Combo and quarter markets need their own entries; an unmapped market stays unmatched.
  5. Side and line. Compare over to more. A different line is a different proposition, so report it, and do not treat its price as the price of this line.

Keep ambiguous and unmatched rows visible. If a name fits two events, the honest output is “ambiguous”, not the first hit. A false match costs more than a missing one.

Keep the two kinds of number apart

  • A PrizePicks line with a tier is not a price. payout_multiplier is null because the board publishes no payout per offer.
  • Each provider has its own clock. Keep observed_at and the feed's timestamp beside any comparison, and do not call a gap an edge until you have checked both.
  • A missing quote is unknown, not zero, and not proof that a book withdrew the market.
  • Our tier belongs to our row. Do not copy it onto the other provider's rows, even for its own PrizePicks entries, without checking how it labels them.

A bounded example you can run

Download pair-with-odds-feed.py, projections.demo.json and broad-odds-feed.sample.json. Python 3.9 or later, standard library only. All sample rows are fictional. It reads one page by default and at most five, and it calls no other provider.

Offline, no key
# Runs offline. Download the client and the two sample files linked above.
python3 pair-with-odds-feed.py \
  --lines-file samples/projections.demo.json \
  --odds-file samples/broad-odds-feed.sample.json
With a key and your own feed export
# One compact page: 1 credit per requested 100 rows. Your feed's rows come from a file you export.
export PRIZEPICKS_API_KEY='your saved key'
python3 pair-with-odds-feed.py --league NBA --pages 1 --odds-file my-feed.json

Output is one JSON line per PrizePicks line, each with a status of same_line, different_line, ambiguous or unmatched, followed by a summary on stderr. Adapt normalize_feed_row to your provider's fields. The sample uses a neutral shape and has not been run against any provider's live response, so verify field and market names against your own.

Budget both sides

Read this side compactly: limit=1000&view=compact costs 10 credits, and an unchanged 304 costs zero. See credit costs. Check both providers' terms before you show the joined data to your users; ours are summarized on the first-call page.