Skip to content

Building your Application#

Once you have reviewed the API's using the Getting Started Guide you'll want to start building your application integration. The following are a few things to think about along with some requirements and recommendations.

Expected Data Flow#

Your API connection is secured by an API key. This key is secret and must not be shared with external parties or users. Always check to be sure the code you write does not inadvertently expose your API key.

Danger

The API key is a secret key associated with your account. Do not share it or expose it in public web pages. Doing so would allow anyone to make queries as if they were you. If you think your API key may have been compromised, contact your Quarter4 Account representative immediately to disable your current key and receive a new key.

To load data and distribute it to your users, you must:

  1. Query the Quarter4 API on a server-to-server layer of your application,
  2. store the result in a local database or similar storage system,
  3. and then send information to your users as they request it.

Here is a sequence diagram that outlines the general process:

sequenceDiagram participant Q4 as Quarter4 Pull API participant Server as Your Backend Server participant DB as Your Data Storage participant API as Your Data API participant App as Your App/Website Note over Server: Your Integration Layer<br>Use the API key for Quarter4 API queries loop Check about every 15 min Server->>+Q4: Request:<br>/{sport}/v2/changes Q4->>+Server: Response:<br>/{sport}/v2/win_losses/example-team-a<br>/{sport}/v2/win_losses/example-team-b Note over Server,DB: Your Data Storage Layer Server->>+Q4: Request: /{sport}/v2/win_losses/example-team-a Q4->>+Server: Response: {...example-team-a data...} Server->>+DB: Store {...example-team-a data...}<br>Team A will win Game 1 Server->>+Q4: Request: /{sport}/v2/win_losses/example-team-a Q4->>+Server: Response: {...example-team-b data...} Server->>+DB: Store {...example-team-b data...}<br>Team B will win Game 2 end rect rgb(245, 245, 245) Note over DB,App: Your API/App Layer<br>Example requests, your requirements will vary App->>+API: What is the prediction for Game 1? API->>DB: Retrieve stored result DB->>API: Return stored result<br>Team A will win Game 1 API->>+App: Team A will win game 1. App->>+API: What is the prediction for Game 2? API->>DB: Retrieve stored result DB->>API: Return stored result<br>Team B will win Game 2 API->>+App: Team B will win game 2. end

This will allow you to use the API key for your Quarter4 API queries from your server, while sending the result to your application users without the api key information.

Important

The response may contain reference to the request URL for links to previous and next pages. These links may contain query variables including the API key. It is important that you do not simply forward the response onto your users but instead store and cache the information on your server and incorporate it into your existing application API.

Changes and Caching#

The pre-game predictions may be updated roughly once every 15 minutes as changes occur. We recommend you query our changes api endpoints for updates no quicker than every 15 minutes to retrieve the most recent changes.

Pre-game predictions will not change once a game has started so if you have already retrieved predictions, you do not need to update them once the startDate passes.

Caching the responses will also improve the overall experience as you can store common entities such as the team and player, then later you can reference that stored information by uuid when querying for event and prediction details instead of reloading or requesting the team and player details with each request.

To check for changes on individual entities, each entity collection has and updatedAt filter option. For example, to retrieve win_loss entities after a specific date, specify a date for the updatedAt[after] filter:

GET https://api.quarter4.io/{sport}/v2/win_losses?updatedAt[after]=2023-04-20T16:56:59+00:00`

The result will contain all the win_loss entities that have been modified after the specific date. Use the last time you checked as the date to retrieve only changes since you last checked.

Additionally, you can use the /{sport}/v2/changes endpoint to retrieve a list of all changes in the last 24 hours (which can also be filtered using updatedAt). For example:

GET https://api.quarter4.io/{sport}/v2/changes?updatedAt[after]=2023-04-20T16:56:59+00:00`
{
  "links": {
    "self": "\/{sport}\/v2\/changes?count=300\u0026updatedAt%5Bafter%5D=2023-04-20T16%3A56%3A59%2B00%3A00"
  },
  "meta": {
    "totalItems": 2,
    "itemsPerPage": 300,
    "currentPage": 1
  },
  "data": [
    {
      "id": "\/{sport}\/v2\/events\/dd86eab1-2e19-324a-8e4e-67199e118d55",
      "attributes": {
        "updatedAt": "2023-04-20T16:57:02+00:00"
      }
    },
    {
      "id": "\/{sport}\/v2\/win_losses\/2baccb07-3ada-3da8-9325-bd95bf19f530",
      "attributes": {
        "updatedAt": "2023-04-20T16:57:02+00:00"
      }
    }
  ]
}

The result contains references to multiple entity types. Use the id property to construct the URL you need to query to get the specific entities changes. For example to retrieve the two entities above you would query:

GET https://api.quarter4.io/{sport}/v2/events/dd86eab1-2e19-324a-8e4e-67199e118d55`
GET https://api.quarter4.io/{sport}/v2/win_losses/2baccb07-3ada-3da8-9325-bd95bf19f530`

Note

The entity updatedAt date changes when any value for the record changes so it may not necessarily indicate a prediction change, just that something in the record changed. In some cases it may not be a property you are interested in but using the changes endpoint and/or the updatedAt filters will drastically cut down on the number of queries you ned to make to ensure your system is up to date with the latest data updates.

Optimize the use of JSON:API#

All Quarter4 API Responses use the JSON:API response format. This format minimizes repetitive data in the request and allows you to provide some control over what data is included or excluded from each request. Here's a simplified example with a few key details:

GET https://api.quarter4.io/{sport}/v2/events?startDate[after]=2022-03-18T15:01:22+00:00&order[startDate]=asc&include=winloss&fields[Event]=uuid,startDate,title&count=1&fields[winloss]=uuid,homeWinProbability,awayWinProbability HTTP/1.1
Accept: application/vnd.api+json

Note

The above example URI shows unencoded [ and ] characters simply for readability. In practice, these characters should be percent-encoded, as noted in the base specification. See “Square Brackets in Parameter Names” in the JSON:API documentation.

{
  "meta": {
    "totalItems": 265,
    "itemsPerPage": 1,
    "currentPage": 1
  },
  "data": [
    {
      "id": "\/{sport}\/v2\/events\/ae4c3bbd-b357-4b66-904a-5dc25b3d3a96",
      "type": "Event",
      "attributes": {
        "startDate": "2022-03-18T16:15:00+00:00",
        "title": "Team A vs Team B",
        "uuid": "ae4c3bbd-b357-4b66-904a-5dc25b3d3a96"
      },
      "relationships": {
        "winloss": {
          "data": {
            "type": "WinLoss",
            "id": "\/{sport}\/v2\/win_losses\/ae4c3bbd-b357-4b66-904a-5dc25b3d3a96"
          }
        }
      }
    }
  ],
  "included": [
    {
      "id": "\/{sport}\/v2\/win_losses\/ae4c3bbd-b357-4b66-904a-5dc25b3d3a96",
      "type": "WinLoss",
      "attributes": {
        "uuid": "ae4c3bbd-b357-4b66-904a-5dc25b3d3a96",
        "homeWinProbability": 33,
        "awayWinProbability": 67
      }
    }
  ]
}

The preceding example includes a list of "Event" results and prediction information for the events in the response. A few key parameters to note are:

The count (and page) parameters#

The count in the query parameters limits the number of results per page in the response. The default is 30 results per page. The response's meta data will contain the totalItems to indicate if there are more imtes available beyond the current page. To query a specific page, include the page parameter starting with 1 as the first page. In this case, for the next result you would include &count=1&page=2 for 1 result per page and results for page 2.

The order parameter (sorting)#

The order query parameter orders the result is a specific order using the following syntax ?order[property]=<asc|desc> for example:

&order[startDate]=asc&order[title]=desc

This order the results first by startDate in ascending order then by title in descending order for items with the same start date. Some APIs may have a default order but in most cases some form of ordering will be desired.

The include parameter#

JSON:API returns results in a relational format and allows you to request a compound document including related resources. In this example, the full entity for the winloss relationship:

 "relationships": {
    "winloss": {
        "data": {
        "type": "WinLoss",
        "id": "\/{sport}\/v2\/win_losses\/ae4c3bbd-b357-4b66-904a-5dc25b3d3a96"
        }
    }
}

will be included in the response under the included list:

"included": [
    {
        "id": "\/{sport}\/v2\/win_losses\/ae4c3bbd-b357-4b66-904a-5dc25b3d3a96",
        "type": "WinLoss",
        "attributes": {
            "uuid": "ae4c3bbd-b357-4b66-904a-5dc25b3d3a96",
            "homeWinProbability": 33,
            "awayWinProbability": 67
        }
    }
]

Your server side application will need to parse the response to locate included items. This format is most useful when requesting longer lists of information where the relationship could be repeated. For example, if you query for a list of events with multiple results and include the homeTeam and awayTeam. On one entry for "Team A" will be in the included list, but multiple events may reference that same team as the home or away team. This reduces the overall result size and repetition.

Multiple related resources can be requested in a comma-separated list such as include=winloss,homeTeam,awayTeam

Note

Due to the size of data resources, the Quarter4 api limits the api to as single depth. You may include and Event's homeTeam but not the homeTeam.nextEvent. To do deeper, call the team endpoint and cache the result to use as necessary.

The fields parameter#

The JSON:API response also include support for Sparse Fieldsets. This allows you to be more specific with which data you would like to see in the response's attributes for specific resources. By default ALL attributes will be included but in many cases you are likely only looking at a few so you may wish to exclude others to reduce the size of the response.

In the example above, the Event's fields are uuid, startDate and title:

fields[Event]=uuid,startDate,title
"id": "\/{sport}\/v2\/events\/ae4c3bbd-b357-4b66-904a-5dc25b3d3a96",
"type": "Event",
"attributes": {
    "startDate": "2022-03-18T16:15:00+00:00",
    "title": "Team A vs Team B",
    "uuid": "ae4c3bbd-b357-4b66-904a-5dc25b3d3a96"
},

while the fields from the winloss for the Even't relationship are: uuid, homeWinProbability, awayWinProbability:

fields[winloss]=uuid,homeWinProbability,awayWinProbability
"id": "\/{sport}\/v2\/win_losses\/ae4c3bbd-b357-4b66-904a-5dc25b3d3a96",
"type": "WinLoss",
"attributes": {
    "uuid": "ae4c3bbd-b357-4b66-904a-5dc25b3d3a96",
    "homeWinProbability": 33,
    "awayWinProbability": 67
}

Note

the fields are case sensitive. In the above example fields[Event] refers to the type of resouse you are querying (Event) however the fields[winloss] refers to the Event's winloss attribute so the winloss case must match that of the Events's attribute. Using fields[WinLoss] would not filter the Event winloss attribute properly.

Additional parameters#

Date field types#

If the API refers to a date, for example the Event start date, there may be additional options for filtering by date range. All system dates are in UTC and use the following syntax ?property[<after|before|strictly_after|strictly_before>]=value for example:

&startDate[after]=2022-09-06T15:37:02+00:00

This results in items where start date is after 2022-09-06T15:37:02+00:00 UTC.

For example to query upcoming events after Sept 6th, 2022 UTC would be:

https://api.quarter4.io/{sport}/v2/events?startDate[after]=2022-09-06&order[startDate]=asc&league.uuid=38344248-9889-11eb-a8ab-0647cdb505d0&page=1&count=30