ohfootball.io

API

Read The Ratings From Your Code

The ratings and the predictions of the current season are available from a public GraphQL API. You do not need an account or a key. Follow the two rules on this page, so that the API stays fast for all callers.

The Endpoint

Send each query to this address as a POST request with a JSON body:

https://api.ohfootball.io/graphql

Say Who You Are

Each request must name a contact. A contact is an email address, or a web address that starts with http:// or https://. Put it in the User-Agent header:

User-Agent: my-football-app/1.0 ([email protected])

If you cannot set User-Agent, for example in the playground at https://api.ohfootball.io/, put the contact in a From header:

From: [email protected]

The default User-Agent of a tool such as curl names no contact, so set your own. The contact lets us reach you if your requests cause a problem.

A query that reads only the schema needs no contact. Its top-level fields must all be __schema, __type, or __typename. So a tool that reads the schema, such as a code generator, works without a contact. These queries count toward the rate limits.

A page on another site cannot call the API from a browser, because the API sends no CORS headers. Call it from a server or a script, or use the playground.

Rate Limits

  • 60 requests a minute from one address. You can send up to 20 at once. After that, you get one more request each second.
  • 20 requests a second from all callers together, with up to 40 at once.

An IPv6 network of size /64 counts as one address. Send your requests one after the other, and keep the answers that you need again.

One query may select at most 300 fields. Each alias and each field of a fragment counts, each time the query uses it. A query may have at most 10000 tokens, and a request body may have at most 1 MiB. These limits hold for queries that read only the schema too.

Errors

When a request breaks a rule, the API sends one of these status codes. The body has the form of a GraphQL error, with the code in its extensions.

400CONTACT_REQUIRED
The request names no contact. The message tells you what to send.
429RATE_LIMITED
The request is over a limit. The Retry-After header gives the number of seconds to wait. Wait that long, then send the request again.
422FIELD_LIMIT_EXCEEDED
The query selects more than 300 fields. Select fewer fields, or send more than one query.
422TOKEN_LIMIT_EXCEEDED
The query has more than 10000 tokens. Send a shorter query.
413BODY_TOO_LARGE
The request body is larger than 1 MiB. Send a shorter query.
{
  "errors": [
    {
      "message": "Too many requests. ...",
      "extensions": {
        "code": "RATE_LIMITED"
      }
    }
  ]
}

Try It

This command asks for the current season. The answer holds its year.

curl https://api.ohfootball.io/graphql \
  -H 'Content-Type: application/json' \
  -H 'User-Agent: my-football-app/1.0 ([email protected])' \
  -d '{"query":"{ currentSeason }"}'

This query asks for the ten teams with the highest rating this season, with the record, the division, and the region of each team. Paste it into the playground:

query TopTen {
  currentSeason
  teams(sort: ELO, limit: 10) {
    name
    city
    division
    region
    record { wins losses ties }
    elo { rating rank }
  }
}

Or send the same query with curl:

curl https://api.ohfootball.io/graphql \
  -H 'Content-Type: application/json' \
  -H 'User-Agent: my-football-app/1.0 ([email protected])' \
  -d '{"query":"query TopTen { currentSeason teams(sort: ELO, limit: 10) { name city division region record { wins losses ties } elo { rating rank } } }"}'

The Playground

The playground runs queries in your browser. The schema, the documentation, and the completion load when the page opens. Before you run a query, replace the text in the From header of the Headers pane with your contact:

{
  "From": "[email protected]"
}

Your browser keeps the Headers pane, so the contact is still there after a reload.

Bulk Data

Do not use the API to download every game or every season. The Kaggle dataset holds every game and rating, and it is published each week.