Zum Inhalt springen

Für Ligen und Verbände

Verbands-API

Die öffentliche Schnittstelle, mit der Ligen und Verbände Spielpläne in Team Manager einspeisen und den Planungsstand ihrer Mannschaften abrufen. Ergebnisse, Tabellen und Statistiken gehören ausdrücklich nicht dazu.

Grundlagen

Basis-URL
https://teammanagerapp.de/api/v1/league
Authentifizierung
Authorization: Bearer tma_live_…
Content-Type
application/json
Zeichensatz
UTF-8
Zeitangaben
UTC, ISO 8601 — reine Daten als YYYY-MM-DD
Version
v1 · jede Antwort trägt X-League-Api-Version

Jeder API-Key gehört zu genau einem Verband; sämtliche Endpunkte arbeiten ausschließlich auf dessen Daten. Keys legt der Verbandsadmin in der Verbandskonsole unter Einstellungen an. Sandbox-Verbände verwenden Keys mit dem Präfix tma_sbx_; ein vertauschter Key wird abgewiesen, statt still Daten zu verschieben.

Tragende Regeln

Idempotenz. Alle schreibenden Endpunkte sind Upserts über externalId — eurer ID für das jeweilige Objekt. Ein wiederholter Aufruf mit denselben Daten ändert nichts. Die IDs müssen pro Verband über alle Saisons hinweg eindeutig sein; trifft ein Upsert auf einen Datensatz aus einer anderen Saison, antwortet die API mit 409 und schreibt nichts. Wer Spielplan-IDs pro Saison neu vergibt, stellt ihnen die Saison voran, etwa 2026-27/F-0421.

Teilweiser Erfolg. Bulk-Endpunkte validieren jeden Datensatz einzeln und melden ihn einzeln. Der Status ist 200 bei vollem Erfolg und 207, sobald mindestens ein Datensatz fehlgeschlagen ist.

Zeiten. Anstoß und Dauer sind optional. Fehlen sie, gilt der Zeitraum des Spieltags und das Team terminiert selbst — das ist der Regelfall. kickoffAt ist ein ISO-8601-Zeitpunkt mit Offset oder Z und damit eindeutig; kickoffLocalTime wird über die Zeitzone des Wettbewerbs sommerzeitfest umgerechnet. Beide schließen sich aus. Antworten liefern immer UTC.

Absagen. Sie laufen ausschließlich über den Status, nie über Löschen — sonst gingen die Rückmeldungen der Spieler verloren.

Datenschutz. Der Rückkanal ist lesend und enthält keine personenbezogenen Daten: keine Namen, keine Rückmeldungen, keine Kaderdaten — nur Status, Zeiten und IDs.

Endpunkte

get/seasonsSaisons abrufen
post/seasonsSaisons anlegen oder aktualisieren
get/competitionsWettbewerbe abrufen
post/competitionsWettbewerbe anlegen oder aktualisieren
get/teamsLigateams abrufen
post/teamsLigateams anlegen oder aktualisieren
get/roundsSpieltage abrufen
post/roundsSpieltage anlegen oder aktualisieren
get/fixturesBegegnungen samt Planungsstand abrufen
post/fixturesBegegnungen anlegen, aktualisieren oder absagen
get/fixtures/{id}Einzelne Begegnung samt Planungsstand abrufen
post/fixtures/csvBegegnungen als CSV einspeisen
post/scheduleKompletten Spielplan in einem Aufruf einspeisen
get/suspensionsSperren und Rückzüge abrufen
post/suspensionsSperre oder Rückzug setzen
delete/suspensions/{id}Sperre vorzeitig aufheben oder Rückzug zurücknehmen
get/metaVersion, Serverzeit, Rate-Limits und Enum-Werte
get/openapi.jsonDiese Beschreibung als OpenAPI-Dokument
post/sandbox/seedBeispielsaison in der Sandbox anlegen
post/sandbox/resetSandbox-Daten löschen
post/sandbox/fixtures/{id}/planningPlanungsstatus einer Seite simulieren
get/seasons

Saisons abrufen

Rate-Limit: 60 Anfragen pro 60 Sekunden.

Parameter

  • limit (query) Seitengröße. Standard 50, Maximum 200.
  • cursor (query) Interne ID des letzten Datensatzes der Vorseite (nextCursor).

Antworten

  • 200 Saisons des Verbands.
  • 401 Kein oder ungültiger API-Key.
  • 403 Key widerrufen, Verband inaktiv oder Modul deaktiviert.
  • 429 Rate-Limit überschritten.
post/seasons

Saisons anlegen oder aktualisieren

Nimmt ein Objekt oder ein Array entgegen. Upsert über externalId.

Rate-Limit: 60 Anfragen pro 60 Sekunden.

Rumpf — ein Objekt oder ein Array davon

FeldTypBeschreibung
externalId*stringID der Saison im System des Verbands. Muss pro Verband über alle Saisons hinweg eindeutig sein. (min. 1 Zeichen, max. 190 Zeichen)
name*stringAnzeigename, z. B. „Saison 2026/27“. (min. 1 Zeichen, max. 200 Zeichen)
startsOn*stringErster Tag der Saison. (Muster ^\d{4}-\d{2}-\d{2}$)
endsOn*stringLetzter Tag der Saison. (Muster ^\d{4}-\d{2}-\d{2}$)
previousSeasonExternalIdstringexternalId der Vorsaison. Grundlage dafür, bestehende Verknüpfungen in die neue Saison zu übernehmen. (min. 1 Zeichen, max. 190 Zeichen)

Antworten

  • 200 Alle Datensätze verarbeitet.
  • 207 Gemischtes Ergebnis — mindestens ein Datensatz ist fehlgeschlagen.
  • 400 Validierungsfehler.
  • 401 Kein oder ungültiger API-Key.
  • 403 Key widerrufen, Verband inaktiv oder Modul deaktiviert.
  • 409 Konflikt, z. B. externalId gehört zu einer anderen Saison.
  • 422 Fachlich unzulässig, z. B. Upsert in eine archivierte Saison.
  • 429 Rate-Limit überschritten.
get/competitions

Wettbewerbe abrufen

Rate-Limit: 60 Anfragen pro 60 Sekunden.

Parameter

  • limit (query) Seitengröße. Standard 50, Maximum 200.
  • cursor (query) Interne ID des letzten Datensatzes der Vorseite (nextCursor).
  • season (query) Auf eine Saison einschränken (externalId).

Antworten

  • 200 Wettbewerbe des Verbands.
  • 401 Kein oder ungültiger API-Key.
  • 403 Key widerrufen, Verband inaktiv oder Modul deaktiviert.
  • 429 Rate-Limit überschritten.
post/competitions

Wettbewerbe anlegen oder aktualisieren

Nimmt ein Objekt oder ein Array entgegen. Upsert über externalId.

Rate-Limit: 60 Anfragen pro 60 Sekunden.

Rumpf — ein Objekt oder ein Array davon

FeldTypBeschreibung
externalId*stringID des Wettbewerbs im System des Verbands. (min. 1 Zeichen, max. 190 Zeichen)
seasonExternalId*stringexternalId der Saison, zu der der Wettbewerb gehört. (min. 1 Zeichen, max. 190 Zeichen)
name*stringAnzeigename, z. B. „Bezirksliga Herren“. (min. 1 Zeichen, max. 200 Zeichen)
typeLEAGUE | CUP | FRIENDLYArt des Wettbewerbs. (Standard "LEAGUE")
sportstringSportart, z. B. „Handball“. (max. 100 Zeichen)
ageGroupstringAltersklasse, z. B. „Herren“. (max. 100 Zeichen)
timezonestringIANA-Zeitzone. Sie hängt am Wettbewerb, nicht am Verband, weil Wettbewerbe regional verortet sind. (min. 1 Zeichen, max. 100 Zeichen, Standard "Europe/Berlin")
defaultKickoffTimestringStandard-Anstoß als Ortszeit, wenn eine Begegnung keinen eigenen trägt. (Muster ^([01]\d|2[0-3]):[0-5]\d$)
defaultDurationMinutesintegerStandarddauer in Minuten, wenn eine Begegnung keine eigene trägt. (max. 600)

Antworten

  • 200 Alle Datensätze verarbeitet.
  • 207 Gemischtes Ergebnis — mindestens ein Datensatz ist fehlgeschlagen.
  • 400 Validierungsfehler.
  • 401 Kein oder ungültiger API-Key.
  • 403 Key widerrufen, Verband inaktiv oder Modul deaktiviert.
  • 409 Konflikt, z. B. externalId gehört zu einer anderen Saison.
  • 422 Fachlich unzulässig, z. B. Upsert in eine archivierte Saison.
  • 429 Rate-Limit überschritten.
get/teams

Ligateams abrufen

Rate-Limit: 60 Anfragen pro 60 Sekunden.

Parameter

  • limit (query) Seitengröße. Standard 50, Maximum 200.
  • cursor (query) Interne ID des letzten Datensatzes der Vorseite (nextCursor).

Antworten

  • 200 Ligateams des Verbands.
  • 401 Kein oder ungültiger API-Key.
  • 403 Key widerrufen, Verband inaktiv oder Modul deaktiviert.
  • 429 Rate-Limit überschritten.
post/teams

Ligateams anlegen oder aktualisieren

Nimmt ein Objekt oder ein Array entgegen. Upsert über externalId.

Rate-Limit: 60 Anfragen pro 60 Sekunden.

Rumpf — ein Objekt oder ein Array davon

FeldTypBeschreibung
externalId*stringID der Mannschaft im System des Verbands. (min. 1 Zeichen, max. 190 Zeichen)
name*stringName der Mannschaft, z. B. „SV Donnerblitz II“. (min. 1 Zeichen, max. 200 Zeichen)
clubNamestringName des Vereins, z. B. „SV Donnerblitz e.V.“. (max. 200 Zeichen)
shortNamestringKurzform für enge Darstellungen. (max. 50 Zeichen)
homeVenueNamestringName der Heimspielstätte. (max. 200 Zeichen)
homeVenueAddressstringAnschrift der Heimspielstätte. (max. 300 Zeichen)

Antworten

  • 200 Alle Datensätze verarbeitet.
  • 207 Gemischtes Ergebnis — mindestens ein Datensatz ist fehlgeschlagen.
  • 400 Validierungsfehler.
  • 401 Kein oder ungültiger API-Key.
  • 403 Key widerrufen, Verband inaktiv oder Modul deaktiviert.
  • 409 Konflikt, z. B. externalId gehört zu einer anderen Saison.
  • 422 Fachlich unzulässig, z. B. Upsert in eine archivierte Saison.
  • 429 Rate-Limit überschritten.
get/rounds

Spieltage abrufen

Rate-Limit: 60 Anfragen pro 60 Sekunden.

Parameter

  • limit (query) Seitengröße. Standard 50, Maximum 200.
  • cursor (query) Interne ID des letzten Datensatzes der Vorseite (nextCursor).
  • competition (query) Auf einen Wettbewerb einschränken (externalId).

Antworten

  • 200 Spieltage des Verbands.
  • 401 Kein oder ungültiger API-Key.
  • 403 Key widerrufen, Verband inaktiv oder Modul deaktiviert.
  • 429 Rate-Limit überschritten.
post/rounds

Spieltage anlegen oder aktualisieren

Nimmt ein Objekt oder ein Array entgegen. Upsert über externalId.

Rate-Limit: 60 Anfragen pro 60 Sekunden.

Rumpf — ein Objekt oder ein Array davon

FeldTypBeschreibung
externalId*stringID des Spieltags im System des Verbands. (min. 1 Zeichen, max. 190 Zeichen)
competitionExternalId*stringexternalId des Wettbewerbs, zu dem der Spieltag gehört. (min. 1 Zeichen, max. 190 Zeichen)
name*stringAnzeigename, z. B. „1. Spieltag“. (min. 1 Zeichen, max. 200 Zeichen)
numberintegerLaufende Nummer des Spieltags. (max. 9007199254740991)
periodStart*stringErster Tag des Zeitraums, in dem der Spieltag ausgetragen wird. (Muster ^\d{4}-\d{2}-\d{2}$)
periodEnd*stringLetzter Tag des Zeitraums. Ohne festen Anstoß terminieren die Teams innerhalb dieses Zeitraums. (Muster ^\d{4}-\d{2}-\d{2}$)

Antworten

  • 200 Alle Datensätze verarbeitet.
  • 207 Gemischtes Ergebnis — mindestens ein Datensatz ist fehlgeschlagen.
  • 400 Validierungsfehler.
  • 401 Kein oder ungültiger API-Key.
  • 403 Key widerrufen, Verband inaktiv oder Modul deaktiviert.
  • 409 Konflikt, z. B. externalId gehört zu einer anderen Saison.
  • 422 Fachlich unzulässig, z. B. Upsert in eine archivierte Saison.
  • 429 Rate-Limit überschritten.
get/fixtures

Begegnungen samt Planungsstand abrufen

Der Rückkanal ist lesend — ein Planungsstatus ändert niemals Ligadaten. Unterstützt ETag und If-None-Match und antwortet mit 304, wenn sich nichts geändert hat.

Rate-Limit: 60 Anfragen pro 60 Sekunden.

Parameter

  • limit (query) Seitengröße. Standard 50, Maximum 200.
  • cursor (query) Interne ID des letzten Datensatzes der Vorseite (nextCursor).
  • status (query) Auf einen Begegnungsstatus einschränken.
  • competition (query) Auf einen Wettbewerb einschränken (externalId).
  • matchday (query) Auf einen Spieltag einschränken (externalId).

Antworten

  • 200 Begegnungen mit Planungsblock.
  • 304 Unverändert seit dem mitgeschickten ETag.
  • 401 Kein oder ungültiger API-Key.
  • 403 Key widerrufen, Verband inaktiv oder Modul deaktiviert.
  • 429 Rate-Limit überschritten.
post/fixtures

Begegnungen anlegen, aktualisieren oder absagen

Nimmt ein Objekt oder ein Array entgegen. Eine Absage ist ein Upsert mit status = CANCELLED, kein Löschen.

Rate-Limit: 60 Anfragen pro 60 Sekunden.

Rumpf — ein Objekt oder ein Array davon

FeldTypBeschreibung
externalId*stringID der Begegnung im System des Verbands. (min. 1 Zeichen, max. 190 Zeichen)
roundExternalIdstringexternalId des Spieltags, zu dem die Begegnung gehört. (min. 1 Zeichen, max. 190 Zeichen)
homeTeamExternalIdstringexternalId der Heimmannschaft. (min. 1 Zeichen, max. 190 Zeichen)
awayTeamExternalIdstringexternalId der Gastmannschaft. (min. 1 Zeichen, max. 190 Zeichen)
venueNamestringSpielstätte, falls abweichend von der Heimspielstätte. (max. 200 Zeichen)
venueAddressstringAnschrift der abweichenden Spielstätte. (max. 300 Zeichen)
statusSCHEDULED | CANCELLEDAbsagen laufen ausschließlich über den Status, nie über Löschen — sonst gingen die Rückmeldungen der Spieler verloren. VOID wird nicht gesetzt, sondern ergibt sich aus einer Sperre.
kickoffAtstring (date-time)Anstoß als ISO-8601-Zeitpunkt mit Offset oder Z — eindeutig, empfohlen. Schließt kickoffLocalTime aus.
kickoffLocalTimestringAnstoß als Ortszeit HH:mm; wird über die Zeitzone des Wettbewerbs und das Datum des Spieltags sommerzeitfest in UTC umgerechnet. Schließt kickoffAt aus. (Muster ^([01]\d|2[0-3]):[0-5]\d$)
durationMinutesintegerDauer in Minuten. Fehlt sie, greift der Standardwert des Wettbewerbs, danach der des Teams. (max. 600)
notestringFreitext, z. B. der Grund einer Absage. (max. 500 Zeichen)

Antworten

  • 200 Alle Datensätze verarbeitet.
  • 207 Gemischtes Ergebnis — mindestens ein Datensatz ist fehlgeschlagen.
  • 400 Validierungsfehler.
  • 401 Kein oder ungültiger API-Key.
  • 403 Key widerrufen, Verband inaktiv oder Modul deaktiviert.
  • 409 Konflikt, z. B. externalId gehört zu einer anderen Saison.
  • 422 Fachlich unzulässig, z. B. Upsert in eine archivierte Saison.
  • 429 Rate-Limit überschritten.
get/fixtures/{id}

Einzelne Begegnung samt Planungsstand abrufen

Rate-Limit: 60 Anfragen pro 60 Sekunden.

Parameter

  • id (path, Pflicht) Interne ID der Begegnung (id aus der Upsert-Antwort).

Antworten

  • 200 Die Begegnung.
  • 304 Unverändert seit dem mitgeschickten ETag.
  • 401 Kein oder ungültiger API-Key.
  • 403 Key widerrufen, Verband inaktiv oder Modul deaktiviert.
  • 404 Objekt existiert nicht in diesem Verband.
  • 429 Rate-Limit überschritten.
post/fixtures/csv

Begegnungen als CSV einspeisen

Gleiche Spalten wie das JSON-Feld, erste Zeile ist die Kopfzeile. Jede Zeile wird einzeln validiert und einzeln gemeldet.

Rate-Limit: 10 Anfragen pro 60 Sekunden.

Antworten

  • 200 Alle Datensätze verarbeitet.
  • 207 Gemischtes Ergebnis — mindestens ein Datensatz ist fehlgeschlagen.
  • 400 Validierungsfehler.
  • 401 Kein oder ungültiger API-Key.
  • 403 Key widerrufen, Verband inaktiv oder Modul deaktiviert.
  • 409 Konflikt, z. B. externalId gehört zu einer anderen Saison.
  • 422 Fachlich unzulässig, z. B. Upsert in eine archivierte Saison.
  • 429 Rate-Limit überschritten.
post/schedule

Kompletten Spielplan in einem Aufruf einspeisen

Saison, Wettbewerb, Ligateams, Spieltage und Begegnungen zusammen — der Hauptweg für die Erstbefüllung. Verarbeitung ist teilweise erfolgreich.

Rate-Limit: 10 Anfragen pro 60 Sekunden.

Rumpf

FeldTypBeschreibung
season*objectSaison, in die eingespeist wird. Wird angelegt oder aktualisiert.
season.externalId*stringID der Saison im System des Verbands. Muss pro Verband über alle Saisons hinweg eindeutig sein. (min. 1 Zeichen, max. 190 Zeichen)
season.name*stringAnzeigename, z. B. „Saison 2026/27“. (min. 1 Zeichen, max. 200 Zeichen)
season.startsOn*stringErster Tag der Saison. (Muster ^\d{4}-\d{2}-\d{2}$)
season.endsOn*stringLetzter Tag der Saison. (Muster ^\d{4}-\d{2}-\d{2}$)
season.previousSeasonExternalIdstringexternalId der Vorsaison. Grundlage dafür, bestehende Verknüpfungen in die neue Saison zu übernehmen. (min. 1 Zeichen, max. 190 Zeichen)
competition*objectWettbewerb. Die Saisonzuordnung ergibt sich aus dem Feld season.
competition.externalId*stringID des Wettbewerbs im System des Verbands. (min. 1 Zeichen, max. 190 Zeichen)
competition.name*stringAnzeigename, z. B. „Bezirksliga Herren“. (min. 1 Zeichen, max. 200 Zeichen)
competition.typeLEAGUE | CUP | FRIENDLYArt des Wettbewerbs. (Standard "LEAGUE")
competition.sportstringSportart, z. B. „Handball“. (max. 100 Zeichen)
competition.ageGroupstringAltersklasse, z. B. „Herren“. (max. 100 Zeichen)
competition.timezonestringIANA-Zeitzone. Sie hängt am Wettbewerb, nicht am Verband, weil Wettbewerbe regional verortet sind. (min. 1 Zeichen, max. 100 Zeichen, Standard "Europe/Berlin")
competition.defaultKickoffTimestringStandard-Anstoß als Ortszeit, wenn eine Begegnung keinen eigenen trägt. (Muster ^([01]\d|2[0-3]):[0-5]\d$)
competition.defaultDurationMinutesintegerStandarddauer in Minuten, wenn eine Begegnung keine eigene trägt. (max. 600)
teamsobject[]Ligateams des Wettbewerbs. (Standard [])
teams[].externalId*stringID der Mannschaft im System des Verbands. (min. 1 Zeichen, max. 190 Zeichen)
teams[].name*stringName der Mannschaft, z. B. „SV Donnerblitz II“. (min. 1 Zeichen, max. 200 Zeichen)
teams[].clubNamestringName des Vereins, z. B. „SV Donnerblitz e.V.“. (max. 200 Zeichen)
teams[].shortNamestringKurzform für enge Darstellungen. (max. 50 Zeichen)
teams[].homeVenueNamestringName der Heimspielstätte. (max. 200 Zeichen)
teams[].homeVenueAddressstringAnschrift der Heimspielstätte. (max. 300 Zeichen)
roundsobject[]Spieltage. Die Wettbewerbszuordnung ergibt sich aus dem Feld competition. (Standard [])
rounds[].externalId*stringID des Spieltags im System des Verbands. (min. 1 Zeichen, max. 190 Zeichen)
rounds[].name*stringAnzeigename, z. B. „1. Spieltag“. (min. 1 Zeichen, max. 200 Zeichen)
rounds[].numberintegerLaufende Nummer des Spieltags. (max. 9007199254740991)
rounds[].periodStart*stringErster Tag des Zeitraums, in dem der Spieltag ausgetragen wird. (Muster ^\d{4}-\d{2}-\d{2}$)
rounds[].periodEnd*stringLetzter Tag des Zeitraums. Ohne festen Anstoß terminieren die Teams innerhalb dieses Zeitraums. (Muster ^\d{4}-\d{2}-\d{2}$)
fixturesobject[]Begegnungen des Spielplans. (Standard [])
fixtures[].externalId*stringID der Begegnung im System des Verbands. (min. 1 Zeichen, max. 190 Zeichen)
fixtures[].roundExternalIdstringexternalId des Spieltags, zu dem die Begegnung gehört. (min. 1 Zeichen, max. 190 Zeichen)
fixtures[].homeTeamExternalIdstringexternalId der Heimmannschaft. (min. 1 Zeichen, max. 190 Zeichen)
fixtures[].awayTeamExternalIdstringexternalId der Gastmannschaft. (min. 1 Zeichen, max. 190 Zeichen)
fixtures[].venueNamestringSpielstätte, falls abweichend von der Heimspielstätte. (max. 200 Zeichen)
fixtures[].venueAddressstringAnschrift der abweichenden Spielstätte. (max. 300 Zeichen)
fixtures[].statusSCHEDULED | CANCELLEDAbsagen laufen ausschließlich über den Status, nie über Löschen — sonst gingen die Rückmeldungen der Spieler verloren. VOID wird nicht gesetzt, sondern ergibt sich aus einer Sperre.
fixtures[].kickoffAtstring (date-time)Anstoß als ISO-8601-Zeitpunkt mit Offset oder Z — eindeutig, empfohlen. Schließt kickoffLocalTime aus.
fixtures[].kickoffLocalTimestringAnstoß als Ortszeit HH:mm; wird über die Zeitzone des Wettbewerbs und das Datum des Spieltags sommerzeitfest in UTC umgerechnet. Schließt kickoffAt aus. (Muster ^([01]\d|2[0-3]):[0-5]\d$)
fixtures[].durationMinutesintegerDauer in Minuten. Fehlt sie, greift der Standardwert des Wettbewerbs, danach der des Teams. (max. 600)
fixtures[].notestringFreitext, z. B. der Grund einer Absage. (max. 500 Zeichen)

Antworten

  • 200 Alle Datensätze verarbeitet.
  • 207 Gemischtes Ergebnis — mindestens ein Datensatz ist fehlgeschlagen.
  • 400 Validierungsfehler.
  • 401 Kein oder ungültiger API-Key.
  • 403 Key widerrufen, Verband inaktiv oder Modul deaktiviert.
  • 409 Konflikt, z. B. externalId gehört zu einer anderen Saison.
  • 422 Fachlich unzulässig, z. B. Upsert in eine archivierte Saison.
  • 429 Rate-Limit überschritten.
get/suspensions

Sperren und Rückzüge abrufen

Rate-Limit: 60 Anfragen pro 60 Sekunden.

Parameter

  • limit (query) Seitengröße. Standard 50, Maximum 200.
  • cursor (query) Interne ID des letzten Datensatzes der Vorseite (nextCursor).

Antworten

  • 200 Sperren und Rückzüge des Verbands.
  • 401 Kein oder ungültiger API-Key.
  • 403 Key widerrufen, Verband inaktiv oder Modul deaktiviert.
  • 429 Rate-Limit überschritten.
post/suspensions

Sperre oder Rückzug setzen

Entfernt die betroffenen Begegnungen bei beiden Mannschaften. Der Grund ist verbandsintern und wird nie an Teams ausgeliefert.

Rate-Limit: 60 Anfragen pro 60 Sekunden.

Rumpf

FeldTypBeschreibung
leagueTeamExternalId*stringexternalId der betroffenen Mannschaft. (min. 1 Zeichen, max. 190 Zeichen)
seasonExternalId*stringexternalId der betroffenen Saison. (min. 1 Zeichen, max. 190 Zeichen)
kindSUSPENSION | WITHDRAWALSUSPENSION ist befristet und verlangt endsOn. WITHDRAWAL ist ein Rückzug und gilt ohne endsOn für den Rest der Saison. (Standard "SUSPENSION")
startsOn*stringErster Tag der Sperre bzw. Tag des Rückzugs. (Muster ^\d{4}-\d{2}-\d{2}$)
endsOnstringLetzter Tag der Sperre. Pflichtfeld bei kind = SUSPENSION, entfällt bei WITHDRAWAL. (Muster ^\d{4}-\d{2}-\d{2}$)
reason*stringBegründung. Verbandsintern — wird niemals an Teams ausgeliefert. (min. 1 Zeichen, max. 1000 Zeichen)

Antworten

  • 201 Sperre angelegt.
  • 400 Validierungsfehler.
  • 401 Kein oder ungültiger API-Key.
  • 403 Key widerrufen, Verband inaktiv oder Modul deaktiviert.
  • 404 Objekt existiert nicht in diesem Verband.
  • 422 Fachlich unzulässig, z. B. Upsert in eine archivierte Saison.
  • 429 Rate-Limit überschritten.
delete/suspensions/{id}

Sperre vorzeitig aufheben oder Rückzug zurücknehmen

Betroffene Begegnungen kehren auf SCHEDULED zurück — und zwar genau die, die diese Sperre entfallen ließ.

Rate-Limit: 60 Anfragen pro 60 Sekunden.

Parameter

  • id (path, Pflicht) Interne ID der Sperre.

Antworten

  • 200 Sperre aufgehoben.
  • 401 Kein oder ungültiger API-Key.
  • 403 Key widerrufen, Verband inaktiv oder Modul deaktiviert.
  • 404 Objekt existiert nicht in diesem Verband.
  • 422 Fachlich unzulässig, z. B. Upsert in eine archivierte Saison.
  • 429 Rate-Limit überschritten.
get/meta

Version, Serverzeit, Rate-Limits und Enum-Werte

Damit eine Anbindung sich selbst prüfen kann.

Rate-Limit: 60 Anfragen pro 60 Sekunden.

Antworten

  • 200 Selbstauskunft.
  • 401 Kein oder ungültiger API-Key.
  • 403 Key widerrufen, Verband inaktiv oder Modul deaktiviert.
  • 429 Rate-Limit überschritten.
get/openapi.json

Diese Beschreibung als OpenAPI-Dokument

Öffentlich, ohne API-Key — die Beschreibung muss lesbar sein, bevor ein Key vorliegt.

Rate-Limit: 60 Anfragen pro 60 Sekunden. Ohne API-Key erreichbar.

Antworten

  • 200 Das OpenAPI-Dokument.
  • 404 Das Ligamodul ist auf dieser Installation nicht eingeschaltet.
  • 429 Rate-Limit überschritten.
post/sandbox/seed

Beispielsaison in der Sandbox anlegen

Legt zwei Wettbewerbe, acht Ligateams, Spieltage und einen kompletten Spielplan an, damit die GET-Endpunkte sofort gegen realistische Daten testbar sind.

Rate-Limit: 10 Anfragen pro 60 Sekunden.

Antworten

  • 200 Beispieldaten angelegt.
  • 401 Kein oder ungültiger API-Key.
  • 403 Key widerrufen, Verband inaktiv oder Modul deaktiviert.
  • 404 Objekt existiert nicht in diesem Verband.
  • 429 Rate-Limit überschritten.
post/sandbox/reset

Sandbox-Daten löschen

Löscht Saisons, Wettbewerbe, Ligateams, Spieltage, Begegnungen, Sperren und Zustellprotokolle. Der Verband selbst, seine Mitglieder und seine API-Keys bleiben bestehen.

Rate-Limit: 10 Anfragen pro 60 Sekunden.

Antworten

  • 200 Sandbox zurückgesetzt.
  • 401 Kein oder ungültiger API-Key.
  • 403 Key widerrufen, Verband inaktiv oder Modul deaktiviert.
  • 404 Objekt existiert nicht in diesem Verband.
  • 429 Rate-Limit überschritten.
post/sandbox/fixtures/{id}/planning

Planungsstatus einer Seite simulieren

Setzt den Planungsstatus direkt und löst denselben Webhook aus wie ein echter Teamvorgang — damit lässt sich die gesamte Anbindung durchspielen, ohne dass ein Verein etwas davon merkt.

Rate-Limit: 60 Anfragen pro 60 Sekunden.

Parameter

  • id (path, Pflicht) Interne ID der Begegnung.

Rumpf

FeldTypBeschreibung
side*HOME | AWAYSeite der Begegnung, deren Planungsstatus gesetzt wird.
status*OPEN | IN_POLL | SCHEDULED | CANCELLEDZielstatus. NOT_LINKED fehlt bewusst: eine einmal simulierte Seite bleibt verknüpft, wie ein echter TeamLink auch.
confirmedDatestringTerminierter Tag, sinnvoll bei status = SCHEDULED. (Muster ^\d{4}-\d{2}-\d{2}$)
kickoffAtstring (date-time)Anstoß als ISO-8601-Zeitpunkt mit Offset oder Z.
durationMinutesintegerDauer in Minuten. (max. 600)

Antworten

  • 200 Neuer Planungsstand der Begegnung.
  • 400 Validierungsfehler.
  • 401 Kein oder ungültiger API-Key.
  • 403 Key widerrufen, Verband inaktiv oder Modul deaktiviert.
  • 404 Objekt existiert nicht in diesem Verband.
  • 429 Rate-Limit überschritten.

Fehler und Rate-Limits

Fehler folgen dem Format der App: ein einziger error-Schlüssel, etwa { "error": "season.externalId: Pflichtfeld" }.

400Validierungsfehler.
401Kein oder ungültiger API-Key.
403Key widerrufen, Verband inaktiv oder Modul deaktiviert.
404Objekt existiert nicht in diesem Verband.
409Konflikt, z. B. externalId gehört zu einer anderen Saison.
422Fachlich unzulässig, z. B. Upsert in eine archivierte Saison.
429Rate-Limit überschritten.

Standard 60 Anfragen pro Minute und Key, Bulk-Endpunkte 10 pro Minute. Bei Überschreitung 429 mit Retry-After in Sekunden.

Webhooks

Alternativ zum Abruf könnt ihr eine URL hinterlegen. Events: fixture.planning_updated und fixture.cancelled. Header: X-Webhook-Event, X-Webhook-Id, X-Webhook-Timestamp und X-Webhook-Signature (HMAC-SHA256 über den rohen Body, hex). Event-ID und Zeitstempel stehen zusätzlich im Body und sind damit von der Signatur gedeckt.

Die Zustellung ist at-least-once: bei Fehlern wird mit exponentiellem Backoff bis zu sechsmal erneut zugestellt. Empfänger müssen deduplizieren — die eventId ist dafür der Schlüssel.

import { createHmac, timingSafeEqual } from "node:crypto";

function verify(rawBody, signatureHeader, secret) {
  const expected = createHmac("sha256", secret).update(rawBody).digest("hex");
  const a = Buffer.from(signatureHeader, "hex");
  const b = Buffer.from(expected, "hex");
  return a.length === b.length && timingSafeEqual(a, b);
}
function verify(string $rawBody, string $signature, string $secret): bool {
    $expected = hash_hmac('sha256', $rawBody, $secret);
    return hash_equals($expected, $signature);
}

Wichtig in beiden Fällen: über den rohen Body signieren, nicht über das erneut serialisierte JSON.

Sandbox

Eine Sandbox ist ein eigener Verband mit eigenen Keys tma_sbx_…. Endpunktumfang und Validierung sind identisch — was in der Sandbox durchgeht, geht auch live durch. Verknüpfungen zu echten Teams sind dort nicht möglich; stattdessen lässt sich der Planungsstatus direkt setzen, was dieselben Webhooks auslöst wie ein echter Teamvorgang. So ist die gesamte Anbindung durchspielbar, ohne dass ein Verein etwas davon merkt.

Versionierung

/api/v1/… ist der stabile Vertrag. Additive Änderungen sind jederzeit ohne Ankündigung möglich: neue Endpunkte, neue optionale Felder im Request, neue Felder in der Antwort. Clients müssen unbekannte Antwortfelder ignorieren.

Brechend sind: ein Feld entfernen oder umbenennen, den Typ ändern, ein bisher optionales Feld zur Pflicht machen, die Bedeutung eines Wertes ändern. Solche Änderungen erscheinen unter /api/v2/…; v1 bleibt danach mindestens 12 Monate bedienbar. Eine abgekündigte Version liefert zusätzlich Deprecation und Sunset.

GET /meta liefert Version, Serverzeit, Rate-Limits und die unterstützten Enum-Werte — damit eine Anbindung sich selbst prüfen kann.