EventGameState
Aggregated live game state for a single event, merged across the sportsbooks covering it. Scores are consensus-selected; temporal fields use sport-aware clock direction; situational fields priority-fill from a fixed book ranking. Every field is optional except the always-present core set — sport coverage varies, so e.g. tennis rows carry sets_home/server while hockey rows carry power_play. Rows also come in a terminal flavour: a fixture that has finished is carried here for 15 minutes after completion with status "final", completed_at, score_type and the final scores. A terminal row is projected from the completion record, not from a live cross-book merge, so it carries no primary_book/book_count/game_period/game_clock and no situational fields — branch on status == "final" before reading those.
Properties
| Name | Type | Description |
|---|---|---|
| home_team | string | Normalized home team name. |
| away_team | string | Normalized away team name. |
| sport | string | Atlas sport id (e.g. `baseball`, `soccer`). |
| league | string | Atlas league id (e.g. `mlb`, `england_-_premier_league`). |
| home_score | integer | Current home score in the natural unit for the sport (runs, points, goals, sets — tennis uses summed set points). Present on live rows and on terminal rows whose `score_type` is `points`; a terminal r |
| away_score | integer | Current away score. Present on live rows and on terminal rows whose `score_type` is `points`; a terminal row with `score_type: "sets"` carries `sets_home`/`sets_away` instead and omits this. |
| is_live | boolean | `true` for a live event; `false` on a carried terminal (finished) row. |
| primary_book | string | The sportsbook whose scores were selected by the merge. Consensus-respecting — if ≥2 books agree on a score the highest-priority book in that group wins. Live rows only — absent on a terminal row. |
| book_count | integer | Number of sportsbooks that contributed live state for this event at merge time. Live rows only — absent on a terminal row. |
| game_period | string | Current period. Sport-specific format: `T5` (MLB top 5), `Q3` (NBA Q3), `2H` (soccer 2nd half), `P2` (NHL P2), `S2` (tennis set 2), `FT` (full time). |
| game_clock | string | Game clock. Countup format (`49:06`) for soccer; countdown format (`5:42`) for basketball/hockey/football. |
| possession | string | Which team has possession (team sports) or is receiving (tennis). |
| server | string | Tennis only — current server. |
| last_play | string | Sport-specific last-play description. |
| is_timeout | boolean | `true` during a timeout. |
| fouls_home | integer | Team fouls (basketball, soccer). |
| fouls_away | integer | |
| corners_home | integer | Soccer only. |
| corners_away | integer | |
| yellow_cards_home | integer | Soccer only. |
| yellow_cards_away | integer | |
| red_cards_home | integer | Soccer only. |
| red_cards_away | integer | |
| power_play | string | Hockey only — which team is on the power play. |
| sets_home | integer | Tennis only — sets won. |
| sets_away | integer | |
| hits_home | integer | Baseball only. |
| hits_away | integer | |
| home_pitcher | string | Baseball only — starting pitcher display name. |
| away_pitcher | string | |
| wickets_home | integer | Cricket only — dismissals. |
| wickets_away | integer | |
| overs | number | Cricket only. |
| batting_team | string | Cricket only. |
| stale | boolean | Only emitted when `true`. Indicates the `primary_book`'s livestate key TTL fell below the aggregator's freshness threshold (~10s) at merge time — scores reflect the last known values; the book has gon |
| aggregator_stale | boolean | Only emitted when `true`. Indicates the SharpAPI aggregator itself hasn't advanced the gen counter for this event's sport in more than ~30s. Broader signal than `stale` — suggests a pipeline hiccup, n |
| status | string | Present only on a carried terminal row, always `final`. Live rows carry no `status` key, so `status == "final"` is the reliable terminal test. |
| completed_at | string | Terminal rows only — when SharpAPI detected the completion (not a league-official final whistle). The 15-minute carry window is measured from this timestamp. |
| score_type | string | Terminal rows only — which fields carry the final result. `sets` for the set-scored sports (`tennis`, `table_tennis`, `volleyball`, `badminton`), whose result is in `sets_home`/`sets_away`; `points` e |
| winner | string | Terminal rows only, and optional even there — omitted when the recorded result does not settle the match (a level score in a sport that cannot draw, a sub-terminal set count, or a snapshot whose score |
JSON Schema
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$id": "https://raw.githubusercontent.com/api-evangelist/sharpapi/main/json-schema/sharpapi-event-game-state-schema.json",
"title": "EventGameState",
"description": "Aggregated live game state for a single event, merged across the sportsbooks covering it. Scores are consensus-selected; temporal fields use sport-aware clock direction; situational fields priority-fill from a fixed book ranking. Every field is optional except the always-present core set — sport coverage varies, so e.g. tennis rows carry sets_home/server while hockey rows carry power_play. Rows also come in a terminal flavour: a fixture that has finished is carried here for 15 minutes after completion with status \"final\", completed_at, score_type and the final scores. A terminal row is projected from the completion record, not from a live cross-book merge, so it carries no primary_book/book_count/game_period/game_clock and no situational fields — branch on status == \"final\" before reading those.",
"x-generated": "2026-10-14",
"x-method": "derived",
"x-generator": "derive-json-schema.py",
"x-source": "openapi/sharpapi-openapi.json#/components/schemas/EventGameState",
"type": "object",
"required": [
"home_team",
"away_team",
"sport",
"league",
"is_live"
],
"properties": {
"home_team": {
"type": "string",
"description": "Normalized home team name."
},
"away_team": {
"type": "string",
"description": "Normalized away team name."
},
"sport": {
"type": "string",
"description": "Atlas sport id (e.g. `baseball`, `soccer`)."
},
"league": {
"type": "string",
"description": "Atlas league id (e.g. `mlb`, `england_-_premier_league`)."
},
"home_score": {
"type": "integer",
"description": "Current home score in the natural unit for the sport (runs, points, goals, sets — tennis uses summed set points). Present on live rows and on terminal rows whose `score_type` is `points`; a terminal row with `score_type: \"sets\"` carries `sets_home`/`sets_away` instead and omits this."
},
"away_score": {
"type": "integer",
"description": "Current away score. Present on live rows and on terminal rows whose `score_type` is `points`; a terminal row with `score_type: \"sets\"` carries `sets_home`/`sets_away` instead and omits this."
},
"is_live": {
"type": "boolean",
"description": "`true` for a live event; `false` on a carried terminal (finished) row."
},
"primary_book": {
"type": "string",
"description": "The sportsbook whose scores were selected by the merge. Consensus-respecting — if ≥2 books agree on a score the highest-priority book in that group wins. Live rows only — absent on a terminal row."
},
"book_count": {
"type": "integer",
"description": "Number of sportsbooks that contributed live state for this event at merge time. Live rows only — absent on a terminal row."
},
"game_period": {
"type": "string",
"description": "Current period. Sport-specific format: `T5` (MLB top 5), `Q3` (NBA Q3), `2H` (soccer 2nd half), `P2` (NHL P2), `S2` (tennis set 2), `FT` (full time)."
},
"game_clock": {
"type": "string",
"description": "Game clock. Countup format (`49:06`) for soccer; countdown format (`5:42`) for basketball/hockey/football."
},
"possession": {
"type": "string",
"enum": [
"home",
"away"
],
"description": "Which team has possession (team sports) or is receiving (tennis)."
},
"server": {
"type": "string",
"enum": [
"home",
"away"
],
"description": "Tennis only — current server."
},
"last_play": {
"type": "string",
"description": "Sport-specific last-play description."
},
"is_timeout": {
"type": "boolean",
"description": "`true` during a timeout."
},
"fouls_home": {
"type": "integer",
"description": "Team fouls (basketball, soccer)."
},
"fouls_away": {
"type": "integer"
},
"corners_home": {
"type": "integer",
"description": "Soccer only."
},
"corners_away": {
"type": "integer"
},
"yellow_cards_home": {
"type": "integer",
"description": "Soccer only."
},
"yellow_cards_away": {
"type": "integer"
},
"red_cards_home": {
"type": "integer",
"description": "Soccer only."
},
"red_cards_away": {
"type": "integer"
},
"power_play": {
"type": "string",
"enum": [
"home",
"away"
],
"description": "Hockey only — which team is on the power play."
},
"sets_home": {
"type": "integer",
"description": "Tennis only — sets won."
},
"sets_away": {
"type": "integer"
},
"hits_home": {
"type": "integer",
"description": "Baseball only."
},
"hits_away": {
"type": "integer"
},
"home_pitcher": {
"type": "string",
"description": "Baseball only — starting pitcher display name."
},
"away_pitcher": {
"type": "string"
},
"wickets_home": {
"type": "integer",
"description": "Cricket only — dismissals."
},
"wickets_away": {
"type": "integer"
},
"overs": {
"type": "number",
"description": "Cricket only."
},
"batting_team": {
"type": "string",
"enum": [
"home",
"away"
],
"description": "Cricket only."
},
"stale": {
"type": "boolean",
"description": "Only emitted when `true`. Indicates the `primary_book`'s livestate key TTL fell below the aggregator's freshness threshold (~10s) at merge time — scores reflect the last known values; the book has gone quiet. Absence of the field means fresh. On live rows it is written only when `true` (absence = fresh); a terminal row always carries it explicitly as `false`."
},
"aggregator_stale": {
"type": "boolean",
"description": "Only emitted when `true`. Indicates the SharpAPI aggregator itself hasn't advanced the gen counter for this event's sport in more than ~30s. Broader signal than `stale` — suggests a pipeline hiccup, not a single-book issue."
},
"status": {
"type": "string",
"enum": [
"final"
],
"description": "Present only on a carried terminal row, always `final`. Live rows carry no `status` key, so `status == \"final\"` is the reliable terminal test."
},
"completed_at": {
"type": "string",
"format": "date-time",
"description": "Terminal rows only — when SharpAPI detected the completion (not a league-official final whistle). The 15-minute carry window is measured from this timestamp."
},
"score_type": {
"type": "string",
"enum": [
"points",
"sets"
],
"description": "Terminal rows only — which fields carry the final result. `sets` for the set-scored sports (`tennis`, `table_tennis`, `volleyball`, `badminton`), whose result is in `sets_home`/`sets_away`; `points` everywhere else, whose result is in `home_score`/`away_score`."
},
"winner": {
"type": "string",
"enum": [
"home",
"away",
"draw"
],
"description": "Terminal rows only, and optional even there — omitted when the recorded result does not settle the match (a level score in a sport that cannot draw, a sub-terminal set count, or a snapshot whose scores never arrived and is recorded as 0-0). A missing `winner` means \"not settled\", not a tie. `draw` is produced only for sports where a level score is a real outcome: `soccer`, `hockey`, `football`, `rugby_union`, `rugby_league`."
}
}
}
Work with this as data
Every JSON Schema here is available over the APIs.io API and to AI agents over MCP.
MCP server
One button, every client — Claude, Cursor, VS Code and the rest.
https://apis.io/mcp
Tools for schemas
4 MCP tools reach this
find_json_schemasBrowse and filter every JSON Schema in the catalog.apis_io_searchSTART HERE — APIs, providers and tags for one query, each with its total.resolveTurn a domain, URL or GitHub org into the provider it belongs to.find_cohortsEvery scored population of providers in the catalog.
Call it yourself
curl for this page
curl "https://apis.io/api/v1/json-schemas/sharpapi-event-game-state"
curl "https://apis.io/api/v1/json-schemas?limit=25"
Calls without X-API-Key need no key. Calls with it need a paid plan — get a key.
Get an API key
Free tier, no form to fill in. Signing in shares your email address with us — we store it to create your key and to recognise you if you sign in with another provider. See our Privacy Policy and Terms.
A second provider on the same verified email joins the account you already have.