Skip to Content
API-ReferenzLive-Spielstand

Live-Spielstatus

Aggregierter Live-Spielstatus — Punktestände, Perioden, Uhren, Ballbesitz und sportartspezifische situative Daten — aus Sportsbooks zusammengeführt zu einer einzigen autoritativen Ansicht pro Event. Eine Zeile pro Live-Spiel, konsensbasiert ausgewählt aus den Büchern, die es abdecken. Ein gerade beendetes Spiel bleibt hier ebenfalls für ein kurzes Zeitfenster als terminale Zeile — siehe Beendete Events.

GET /api/v1/gamestate GET /api/v1/gamestate/{sport}

AuthentifizierungPermalink for this section

Erfordert API-Schlüssel. Verfügbar mit dem Game State Add-on (79 $/Monat) oder der Enterprise-Stufe. Schlüssel ohne eines von beiden erhalten 403 tier_restricted mit addon: "game_state" im Fehler-Body. Fügen Sie das Add-on über die Abrechnungsseite  bei jedem kostenpflichtigen Plan hinzu (Hobby / Pro / Sharp); Enterprise-Schlüssel haben es bereits enthalten.

Live-Spielstatus wird auch über den Kanal gamestate per SSE und WebSocket gestreamt — siehe Streaming unten. (Streaming-Zugriff erfordert das WebSocket Add-on oder Enterprise, zusätzlich zur oben genannten Game State- Anforderung.)

PfadparameterPermalink for this section

ParameterTypBeschreibung
sportstring(optional) Einzelne zurückzugebende Sportart. Entspricht einer bekannten Atlas-Sportart (soccer, tennis, esports, basketball, table_tennis, baseball, hockey, cricket, volleyball, handball, football, olympics, darts, boxing, rugby_league, mma, aussie_rules, snooker, rugby_union, golf, floorball, water_polo, lacrosse, futsal, other). Groß-/Kleinschreibung wird ignoriert. Eine unbekannte Sportart gibt ein leeres data-Objekt zurück — ebenso eine unterstützte Sportart, für die gerade nichts live ist; siehe Hinweis unten.

Ein leeres data-Objekt bedeutet nicht, dass die Sportart nicht unterstützt wird. Game State wird pro Sportart in einem gamestate:{sport}-Key mit 60 Sekunden TTL zusammengeführt (GAMESTATE_TTL, bewusst das Doppelte des 30-Sekunden-livestate-Fensters). Ist nichts live, läuft der Key ab und die Antwort lautet {"data":{}} — identisch zur Antwort für eine nicht abgedeckte Sportart. Mehrere der oben genannten Sportarten sind saisonal.

Mit GET /api/v1/sports sehen Sie event_count und live_count je Sportart. other ist der Fallback-Bucket für von Atlas nicht zugeordnete Sportarten.

Ohne den Pfadparameter werden alle Sportarten mit Live-Events zurückgegeben.

AbfrageparameterPermalink for this section

Beide gelten für /api/v1/gamestate und /api/v1/gamestate/{sport}. Werte sind case-insensitiv und werden getrimmt. Lassen Sie beide weg, erhalten Sie die Standardmenge: alles Live plus die beendeten Zeilen, die sich noch im Übertragungsfenster befinden.

ParameterAkzeptiertBeschreibung
statusfinalGibt ausschließlich die übertragenen beendeten Zeilen zurück — das Gegenstück zu /events?status=final. Jeder andere Wert ist ein 400 validation_error (siehe unten). Es gibt keinen Wert live: Live-Zeilen sind die Standardmenge, und ?is_live=true fordert sie allein an.
is_livetrue, falsetrue gibt nur Live-Zeilen zurück und schließt damit jede beendete Zeile aus. false gibt nur Nicht-Live-Zeilen zurück, was heute die übertragenen beendeten Zeilen bedeutet. Jeder andere Wert — einschließlich 1 und 0 — ist ein 400 validation_error.

Ein unbekannter Wert wird abgelehnt, nicht ignoriert. ?status=zzz und ?is_live=1 liefern beide 400 mit einem validation_error-Body, der die akzeptierte Menge nennt, statt stillschweigend die ungefilterten oder die falschen Zeilen zurückzugeben.

{ "error": { "code": "validation_error", "message": "is_live must be one of: true, false", "details": { "parameter": "is_live", "accepted": ["true", "false"] } } }

?is_live=1 wurde früher als false gelesen und lieferte genau die Zeilen, die der Aufrufer ausschließen wollte; jetzt ist es ein 400. Wenn Sie 1 / 0 senden, stellen Sie auf true / false um.

Antwort-HüllePermalink for this section

{ "data": { "<sport>": { "<event_id>": { ...event state... } } }, "updated_at": "2026-04-23T23:55:01.234Z" }

Jeder Event-Status ist über seine kanonische event_id innerhalb seines Sportart- Buckets indiziert. updated_at ist die Serverzeit, zu der diese Antwort erstellt wurde — verwenden Sie sie, um die Aktualität bei Polling abzuschätzen.

Event-Status-FelderPermalink for this section

Jedes Feld ist optional, sofern nicht anders angegeben. Das Vorhandensein variiert je nach Sportart — Tennis-Events enthalten sets_home / server; Hockey-Events enthalten power_play; Soccer-Events enthalten corners_* / yellow_cards_*; usw.

Immer vorhandenPermalink for this section

FeldTypHinweise
home_teamstringNormalisierter Name des Heimteams
away_teamstringNormalisierter Name des Auswärtsteams
sportstringSportart-Bucket (baseball, soccer, …)
leaguestringAtlas-Liga-ID (z. B. mlb, england_-_premier_league)
home_scoreintegerAktueller Heim-Punktestand in der natürlichen Einheit für die Sportart (Runs, Punkte, Tore, Sätze — Tennis verwendet summierte Satzpunkte)
away_scoreintegerAktueller Auswärts-Punktestand
is_livebooleantrue bei einem Live-Event. false bei einer übertragenen beendeten Zeile — siehe Beendete Events
primary_bookstringDas Buch, aus dem die zusammengeführten Punktestände ausgewählt wurden. Konsensbasiert — höherwertige Bücher gewinnen bei Gleichstand
book_countintegerAnzahl der Sportsbooks, die zum Zeitpunkt des Mergens Live-Status für dieses Event beigetragen haben

„Immer vorhanden” heißt: immer vorhanden auf einer Live-Zeile. Eine übertragene beendete Zeile wird aus dem Abschluss-Datensatz gebildet, nicht aus einem Live-Merge, und trägt daher weder primary_book noch book_count und kein game_period / game_clock. Auch ihre Punktestandsfelder hängen von der Sportart ab: satzbasierte Sportarten tragen sets_home / sets_away statt home_score / away_score. Prüfen Sie status === "final", bevor Sie eines dieser Felder lesen. Die vollständige terminale Form steht unter Beendete Events.

Zeitlich (die meisten Mannschaftssportarten)Permalink for this section

FeldTypBeispiel
game_periodstring"T5" (MLB Anfang des 5.), "Q3" (NBA Q3), "2H" (Soccer 2. Halbzeit), "P2" (NHL), "S2" (Tennis 2. Satz), "FT" (Spielende)
game_clockstring"49:06" für hochzählende Sportarten (Soccer), "5:42" für herunterzählende Sportarten (Basketball, Hockey)

SituativPermalink for this section

FeldTypHinweise
possession"home" | "away"Welches Team in Ballbesitz ist (Mannschaftssportarten) oder aufschlägt (Tennis)
server"home" | "away"Nur Tennis — aktueller Aufschläger
last_playstringSportartspezifische Beschreibung des letzten Spielzugs, sofern verfügbar
is_timeoutbooleantrue während eines Timeouts

SportartspezifischPermalink for this section

FeldSportartTyp
fouls_home, fouls_awaybasketball, soccerinteger
corners_home, corners_awaysoccerinteger
yellow_cards_home, yellow_cards_awaysoccerinteger
red_cards_home, red_cards_awaysoccerinteger
power_playhockey"home" | "away"
sets_home, sets_awaytennisinteger (gewonnene Sätze)
hits_home, hits_awaybaseballinteger
home_pitcher, away_pitcherbaseballstring — Anzeigename des Starting Pitchers
wickets_home, wickets_awaycricketinteger
overscricketfloat
batting_teamcricket"home" | "away"

AktualitätPermalink for this section

FeldTypBedeutung
staletrue (sonst weggelassen)Die TTL des Livestate-Schlüssels von primary_book ist zum Zeitpunkt des Mergens unter den Aktualitätsschwellenwert des Aggregators (~10s) gefallen. Punktestände sind die zuletzt bekannten Werte; das Buch ist verstummt. Behandeln Sie Punktestände und Periode des Events als möglicherweise hinter dem tatsächlichen Spielstatus zurückbleibend.
aggregator_staletrue (sonst weggelassen)Der SharpAPI-Aggregator selbst hat seit über ~30s keinen neuen gamestate:{sport}-Shard für diese Sportart geschrieben. Breiteres Signal als stale — weist auf eine Pipeline-Störung hin, nicht auf ein Problem mit einem einzelnen Buch. Wenn Sie dies anhaltend sehen, kontaktieren Sie den Support.

Abwesenheit = aktuell. Sowohl stale als auch aggregator_stale werden nur geschrieben, wenn sie zutreffen, was die Payload kompakt hält. Wenn Sie sie nicht bei einem Event sehen, gelten die Daten als aktuell.

Beendete EventsPermalink for this section

Ein Spiel verschwand früher in dem Moment aus /gamestate, in dem es endete — das Endergebnis war nur für Clients sichtbar, die zufällig während des letzten Live-Zyklus gepollt haben. Beendete Events bleiben jetzt 15 Minuten nach Spielende als terminale Zeile auf diesem Endpoint, sodass jeder Poller mit vernünftigem Intervall das Endergebnis mindestens einmal sieht.

Das Fenster ist serverseitig und beträgt derzeit 15 Minuten (GAMESTATE_TERMINAL_CARRY_SECONDS, Standard 900). Danach verschwindet die Zeile endgültig; das abgeschlossene Ergebnis bleibt über /api/v1/events?status=final verfügbar — die Quelle, aus der die terminale Zeile stammt.

So sieht eine terminale Zeile ausPermalink for this section

{ "home_team": "Skelleftea AIK", "away_team": "Geneva Servette HC", "sport": "hockey", "league": "champions_hockey_league", "home_score": 2, "away_score": 1, "score_type": "points", "winner": "home", "status": "final", "completed_at": "2026-09-10T18:54:03Z", "is_live": false, "stale": false }
FeldTypHinweise
status"final"Nur auf einer terminalen Zeile vorhanden. Live-Zeilen tragen überhaupt keinen status-Schlüssel, daher ist status === "final" der verlässliche Test — leiten Sie ihn nicht aus is_live ab.
completed_atstringISO 8601 — der Zeitpunkt, zu dem SharpAPI den Abschluss erkannt hat, nicht der offizielle Schlusspfiff der Liga. Das Übertragungsfenster wird ab diesem Zeitstempel gemessen.
score_type"points" | "sets"Welche Felder das Ergebnis tragen. "sets" für die satzbasierten Sportarten (tennis, table_tennis, volleyball, badminton); "points" überall sonst.
winner"home" | "away" | "draw"Optional — wird weggelassen, wenn das Ergebnis nicht bestimmbar ist; siehe unten. "draw" entsteht nur bei Sportarten, in denen ein Gleichstand ein echtes Resultat ist (soccer, hockey, football, rugby_union, rugby_league).
is_livefalseImmer explizit false, damit jede is_live-gesteuerte Darstellung die Zeile als nicht live behandelt.
stalefalseImmer explizit false. Dies ist die einzige Stelle, an der stale erscheint, ohne zuzutreffen — die Regel „Abwesenheit = aktuell” oben gilt nur für Live-Zeilen.

Endergebnisse verwenden die Live-Feldnamen, je nach Sportart. Eine punktbasierte Sportart legt ihren Zählstand in home_score / away_score. Eine satzbasierte Sportart legt ihre Satzanzahl in sets_home / sets_away und trägt kein home_score / away_score — ein Tennis-Endstand ist 2:1 in Sätzen, und das in home_score zu legen würde mit den Spielpunkten der Live-Zeile kollidieren:

{ "home_team": "Mikhail Biserov", "away_team": "Vasily Yugov", "sport": "table_tennis", "league": "pro_league", "sets_home": 2, "sets_away": 1, "score_type": "sets", "winner": "home", "status": "final", "completed_at": "2026-09-10T18:55:25Z", "is_live": false, "stale": false }

winner kann fehlen, und das hat eine Bedeutung. Das Feld wird weggelassen, wenn das erfasste Ergebnis das Spiel nicht entscheidet:

  • ein Gleichstand in einer Sportart ohne Unentschieden (Basketball, Handball, E-Sport, Baseball …) — das Spiel ging in die Verlängerung, wurde abgebrochen, oder der Feed endete vor der Entscheidung;
  • eine sub-terminale Satzanzahl in einer satzbasierten Sportart (wer weniger als zwei Sätze führt, kann kein Format gewonnen haben);
  • ein Snapshot, dessen Punktestände nie eintrafen, der als 0-0 erfasst wird. Deshalb ist ein 0-0 ohne winner nicht dasselbe wie ein echtes torloses Unentschieden — ein echtes trägt "winner": "draw".

Behandeln Sie ein fehlendes winner als „nicht entschieden”, nicht als Gleichstand. Wenn Sie werten oder abrechnen, überspringen Sie diese Zeilen.

Welche Felder eine terminale Zeile nicht trägtPermalink for this section

Eine terminale Zeile wird aus dem Abschluss-Datensatz projiziert, nicht aus einem Live-Merge über mehrere Bücher, daher fehlen diese Live-Felder schlicht: primary_book, book_count, game_period, game_clock sowie jedes situative Feld (possession, corners_*, power_play, in_play, die Tennis-Siegwahrscheinlichkeits-Familie und so weiter). Lesen Sie sie erst, nachdem Sie geprüft haben, dass die Zeile nicht status: "final" ist.

Beendete Events filternPermalink for this section

Sie möchtenAnfrage
Nur Live-Zeilen (Verhalten vor der Übertragung)?is_live=true
Nur beendete Zeilen?status=final
Beides (Standard)kein Parameter
# Nur die Endergebnisse der letzten 15 Minuten, eine Sportart curl "https://api.sharpapi.io/api/v1/gamestate/soccer?status=final" \ -H "X-API-Key: YOUR_API_KEY" # Genau das, was Sie vor der Übertragung bekommen haben curl "https://api.sharpapi.io/api/v1/gamestate?is_live=true" \ -H "X-API-Key: YOUR_API_KEY"

Ist ein beendetes Event irgendwo noch live, gewinnt die Live-Zeile. Eine event_id, die sowohl in der Live-Menge als auch in der übertragenen Menge auftaucht, wird einmal zurückgegeben — als Live-Zeile. Ein Buch, das das Spiel noch quotiert, hält es live, bis jedes Buch es fallengelassen hat.

BeispielanfragenPermalink for this section

# Alle Live-Events über alle Sportarten curl "https://api.sharpapi.io/api/v1/gamestate" \ -H "X-API-Key: YOUR_API_KEY" # Eine Sportart curl "https://api.sharpapi.io/api/v1/gamestate/soccer" \ -H "X-API-Key: YOUR_API_KEY"

BeispielantwortPermalink for this section

{ "data": { "soccer": { "argentina_-_primera_division_bocajuniors_defensayjusticia_2026-04-23": { "home_team": "Defensa y Justicia", "away_team": "Boca Juniors", "sport": "soccer", "league": "argentina_-_primera_division", "home_score": 0, "away_score": 1, "game_period": "2H", "game_clock": "49:06", "is_live": true, "possession": "away", "corners_home": 1, "corners_away": 0, "fouls_home": 0, "fouls_away": 0, "yellow_cards_home": 0, "yellow_cards_away": 0, "red_cards_home": 0, "red_cards_away": 0, "primary_book": "draftkings", "book_count": 6 }, "chile_-_primera_division_concepcion_palestino_2026-04-24": { "home_team": "Palestino", "away_team": "Concepción", "sport": "soccer", "league": "chile_-_primera_division", "home_score": 0, "away_score": 0, "is_live": true, "primary_book": "unibet", "book_count": 1, "stale": true }, "montenegro_-_prva_liga_bokelj_otrantolympiculcinj_2026-04-23": { "home_team": "Bokelj", "away_team": "FK Otrant-Olympic Ulcinj", "sport": "soccer", "league": "montenegro_-_prva_liga", "home_score": 2, "away_score": 1, "score_type": "points", "winner": "home", "status": "final", "completed_at": "2026-04-23T23:48:55Z", "is_live": false, "stale": false } } }, "updated_at": "2026-04-23T23:55:01.234Z" }

Die dritte Zeile ist eine terminale Zeile: Das Spiel endete rund sechs Minuten, bevor diese Antwort erzeugt wurde, wird also mit status: "final" und seinem Endstand übertragen und trägt kein primary_book, book_count, game_period oder game_clock.

Cross-Book-Merge-ModellPermalink for this section

Die Felder jedes Events werden aus dem Livestate-Snapshot jedes Sportsbooks über einen dreiklassigen Algorithmus zusammengeführt:

  • Klasse A — Punktestände werden per Konsens ausgewählt: Unter den Büchern mit dem am weitesten fortgeschrittenen Periodenrang gewinnt der höchste Gesamtpunktestand mit ≥2 Unterstützern. Ein einzelnes Buch, das einen Ausreißer-Score meldet (häufig in den ersten Sekunden einer Punkteänderung oder von einem fehlerhaften Adapter), wird abgelehnt.
  • Klasse B — Zeitliche Felder (game_period, game_clock) werden basierend auf der sportartabhängigen Uhrenrichtung — herunterzählend vs. hochzählend — und dem Periodenrang ausgewählt.
  • Klasse C — Situative Felder (possession, corners_*, etc.) werden prioritätsbasiert aus einem festen Buchranking gefüllt.

primary_book gibt an, aus welchem Buch die siegreichen Punktestände stammten. book_count ist die Gesamtzahl der Bücher, die zum Zeitpunkt des Mergens irgendeinen Status zum Event beigetragen haben.

StreamingPermalink for this section

Jede Live-Aktualisierung, die der REST-Endpoint beim nächsten Poll anzeigen würde, löst auch ein gamestate:update-Event auf den Streaming-Kanälen aus:

Streaming-Clients erhalten einen initialen gamestate:snapshot mit dem vollständigen aktuellen Status (eine flache Liste von Event-Zeilen), dann gamestate:update- Events mit geänderten Zeilen während des Mergens und gamestate:removed- Events, wenn Events aus der Live-Menge fallen.

Ein beendetes Event bleibt als status: "final"-Zeile für das Fenster aus Beendete Events in der gestreamten Slate und wird einmal mit einem gamestate:final-Frame angekündigt.

AbschlussmeldungenPermalink for this section

Wenn ein Event endet, sendet jeder Transport genau einen gamestate:final-Frame dafür. Er trägt die terminale Zeile des Events — dieselbe Form wie die REST-Zeile, plus event_id.

WebSocket:

{"type":"gamestate:final","seq":48213,"global_seq":"48213","data":[{"event_id":"atp_jdoe_rroe_2026-07-03","home_team":"J. Doe","away_team":"R. Roe","sport":"tennis","league":"atp","sets_home":1,"sets_away":2,"score_type":"sets","winner":"away","status":"final","completed_at":"2026-07-03T19:42:10Z","is_live":false,"stale":false}]}

SSE (dieselbe {"data": [...]}-Hülle wie gamestate:update):

event: gamestate:final data: {"data":[{"event_id":"atp_jdoe_rroe_2026-07-03","home_team":"J. Doe","away_team":"R. Roe","sport":"tennis","league":"atp","sets_home":1,"sets_away":2,"score_type":"sets","winner":"away","status":"final","completed_at":"2026-07-03T19:42:10Z","is_live":false,"stale":false}]}
  • Gleicher Zugang, gleiche Filter wie gamestate:update. Wer gamestate:update erhält, erhält auch gamestate:final; Ihre sport/league-Filter gelten. Ohne Game-State-Zugang erhalten Sie keines von beiden.
  • WebSocket spielt ihn erneut ab. Wie gamestate:update und gamestate:removed liegt er im Replay-Puffer und wird bei einem Reconnect mit from_seq erneut gesendet. SSE-Gamestate-Frames sind nicht fortsetzbar.
  • Eine Ankündigung, nicht die einzige Zustellung. Dieselbe Zeile steht während des ganzen Fensters auch in der Slate (gamestate:snapshot und gamestate:update).

„Einmal pro Event“ kann sich gelegentlich wiederholen — deduplizieren Sie auf (event_id, completed_at). Sie können gamestate:final für dasselbe Event mehr als einmal erhalten. event_id und completed_at sind bei jeder Wiederholung identisch; verwerfen Sie einen Frame, dessen Paar Sie schon verarbeitet haben. Das ist immer sicher, weil die Zeile weiterhin in der Slate steht.

Rate Limits & KontingentePermalink for this section

Rate Limits richten sich nach Ihrer Basisstufe, nicht nach dem Add-on — Hobby-Schlüssel behalten ihre 120 req/min, Pro behalten 300, Sharp behalten 1.000, Enterprise individuell. Siehe Pricing . /gamestate zählt genauso wie andere REST-Aufrufe zum Pro-Minute-Kontingent.

FehlerbehebungPermalink for this section

  • 403 tier_restricted mit addon: "game_state" — Ihr Schlüssel hat das Game State Add-on nicht. Fügen Sie es über Billing  für 79 $/Monat hinzu oder upgraden Sie auf Enterprise.
  • 400 validation_error mit parameter: "status" — der einzige akzeptierte ?status=-Wert ist final. Es gibt keinen Wert live; Live-Zeilen sind die Standardmenge, oder fordern Sie sie allein mit ?is_live=true an.
  • 400 validation_error mit parameter: "is_live" — ?is_live= akzeptiert nur true / false. 1 und 0 werden abgelehnt; früher wurden sie als false gelesen und lieferten das Gegenteil des Gewünschten.
  • Eine Zeile mit status: "final" und is_live: false — kein Fehler. Das ist ein beendetes Event innerhalb seines 15-Minuten-Fensters. Filtern Sie mit ?is_live=true für das Verhalten von vorher.
  • primary_book / book_count fehlen — Sie lesen eine terminale Zeile. Prüfen Sie status, bevor Sie Live-Felder lesen.
  • Leeres data-Objekt — keine Live-Events im Bereich. Dies ist häufig zwischen Events bei kleineren Sportplänen. Pollen Sie erneut.
  • Events mit stale: true — das primäre Buch ist verstummt. Punktestände können hinterherhinken; erwägen Sie, sie herauszufiltern oder einen UI- Indikator anzuzeigen.
  • Events mit aggregator_stale: true — der SharpAPI-Aggregator hat diese Sportart seit >30s nicht aktualisiert. Wenn anhaltend, kontaktieren Sie den Support; ein kurzer Anstieg kann während Redeploys auftreten.
  • Dieselbe Partie erscheint zweimal unter verschiedenen event_ids — bekannte Einschränkung bei einigen regionalen Ligen, in denen Sportsbooks inkonsistente Liganamen verwenden. Verwenden Sie (home_team, away_team) als sekundären Dedup-Schlüssel auf dem Client, bis die verbleibenden Alias-Lücken geschlossen sind.
Last updated on