A college football API is usually one of two things: a statistics and results source (scores, drives, recruiting, rankings) or an odds source (what sportsbooks are offering on each game). Developers searching for one often want the first. ZippyOddsAPI is the second: it returns college football games on the board with each book's spreads, totals, moneylines and, where books offer them, props, and it isn't a source of results or play-by-play.
What makes college harder than the pro leagues is size. A Saturday slate can run to dozens of games, many teams share a nickname or most of a name, and the lines are often lopsided in a way NFL lines rarely are. This guide covers what to expect from each kind of source and how to handle those three problems in code.
Stats source or odds source
A college football data API on the stats side answers questions like who won, by how much, how each drive went and how a team's offense rates. That's the data for rankings, recruiting tools and most fantasy work. Check the provider's own documentation and terms for what you may store and show.
An odds source answers a different question: what the market thinks will happen, and what it costs to act on a different view. If your project is a betting model, you need both, joined on teams and date. The sports API guide sets out the main categories of sports data and how they fit together.
The same applies to searches for an NCAA API. The governing body publishes a lot of results and rankings on its own sites, and community clients for those sites exist. What any of them permits is for their own terms to say, so read those before you build.
What ZippyOddsAPI returns for college games
College football is the league id ncaaf, and college basketball is ncaab. If you're after a college basketball API for prices, everything below works the same way with league=ncaab, and the team name problem is, if anything, worse.
curl -s "https://zippyoddsapi.com/v1/events?league=ncaaf&limit=200" \
-H "Authorization: Bearer $ZIPPYODDS_KEY"
That costs 1 credit and returns games soonest first, each with start_time, home, away and status. /v1/odds?league=ncaaf adds each book's prices for 2 credits. A league id being accepted doesn't mean it has games on the board right now: /v1/leagues gives the current count, and the coverage page shows which books are feeding.
Paging through a full slate
/v1/events returns up to 500 rows a page and /v1/odds up to 200, and a paged answer always says whether more remain. On a big college Saturday, follow the cursor instead of assuming one page is everything:
import os
import requests
url = "https://zippyoddsapi.com/v1/odds"
headers = {"Authorization": f"Bearer {os.environ['ZIPPYODDS_KEY']}"}
params = {"league": "ncaaf", "markets": "spread,total"}
games = []
while True:
body = requests.get(url, params=params, headers=headers, timeout=10).json()
games.extend(body["data"])
if not body["meta"]["has_more"]:
break
params["cursor"] = body["meta"]["next_cursor"]
Each page costs 2 credits. Pass the cursor back unchanged with the same filters. If the board moves on and the cursor expires, you get 409 cursor_expired, and the fix is to start again from the first page.
The team name problem
College football has far more teams than any pro league, and their names overlap. Kentucky and Western Kentucky are different schools. So are Miami and Miami (Ohio), and a book that writes one without the qualifier makes the other look like the same game. Several schools share a nickname. A false merge of two different games doesn't just break a scoreboard: in an odds app it invents a price gap that looks like a huge edge.
ZippyOddsAPI joins two listings into one event only when it's sure they're the same game, and errs towards leaving them apart. Your own code joining a college football data API to odds should do the same:
- Match on the full name, the opponent and the date together. One alone proves nothing.
- Don't key on the nickname. Team ids in ZippyOddsAPI are built from the league and the last word of the team's name, such as
ncaaf_wildcats, and in college plenty of schools end in the same word. Treat the id as a label on the board and keep the fullnamein your match. - Don't trust
abbras the school's own abbreviation. It's built from the first letters of the name's words, up to three. - Review the leftovers by hand. A game that matches twice, or not at all, is the one to look at.
/v1/teams?league=ncaaf lists only teams with something on the board now. It isn't a directory of every program, so don't use it as one.
Lopsided lines, and why margin removal matters more
College games produce prices that pro games rarely do. Say a heavy favorite is -1200 and the underdog +750:
| Side | Price | Implied chance |
|---|---|---|
| Favorite | -1200 | 92.31% |
| Underdog | +750 | 11.76% |
The two add up to 104.07%. Divide each by 1.0407 and you get 88.70% and 11.30%, a fair price of about -785 and +785.
Dividing evenly is the simplest method, and on lopsided lines it's the least accurate. Books tend to put more of their margin on the longshot, so the even split understates the favorite. ZippyOddsAPI removes margin with Shin's method, which allows for that, so its fair chance for the favorite comes out a little higher than 88.70%. If you devig college lines yourself, test your method on the extremes, not on -110 pairs.
Before you build
- Decide whether you need results, odds or both, and pick a source for each.
- Page through every slate, and follow
next_cursorto the end. - Match teams on more than one field, and leave doubtful games unmatched.
- Check the age of each price, which is in
updated_aton every book.
The sports odds API guide covers how ZippyOddsAPI reads and dates prices, and the docs cover every parameter and how to get a key.