Was du damit bauen kannst
Die API ist für Vereins-Admins gedacht, die ein wenig programmieren können und sich wiederkehrende Arbeit sparen wollen. Ein paar Ideen:
- Die heute freien Plätze oder die nächsten Vereinstermine auf der Vereinswebsite anzeigen.
- Die Mitgliederliste jede Nacht in eine Tabelle oder die Buchhaltung exportieren.
- Die Platzsperren für die gesamte Mannschaftsmeisterschaft aus einer Terminliste anlegen.
- Die Buchungen des Tages auf einem Bildschirm im Clubhaus zeigen.
- Automatisch eine Neuigkeit veröffentlichen, sobald die Ergebnisse der Liga da sind.
Es gibt keine eigene „öffentliche API“ mit weniger Funktionen: Ein Schlüssel verwendet dieselben Endpunkte wie die Clubnetz-App selbst.
API-Schlüssel erstellen
- Melde dich als Admin deines Vereins bei Clubnetz an.
- Öffne im Menü Admin → API-Schlüssel.
- Wähle Neuer Schlüssel, gib ihm einen Namen, der sagt, wofür er da ist, und lege fest, wie lange er gültig ist.
- Entscheide, was er darf: Nur lesen für Exporte und Anzeigen, Lesen und schreiben, wenn er etwas ändern soll.
- Kopiere den Schlüssel. Er beginnt mit
cnz_und wird nur einmal angezeigt.
Verwende einen Schlüssel pro Skript oder Werkzeug. So siehst du, welcher zuletzt verwendet wurde, und kannst einen einzelnen widerrufen, ohne die anderen lahmzulegen.
Die erste Anfrage
Sende den Schlüssel im Header Authorization mit. Diese Anfrage listet die Plätze deines Vereins auf:
curl -H "Authorization: Bearer cnz_DEIN_SCHLUESSEL" \
https://my.clubnetz.app/api/Clubs/12/Courts
Die Antwort ist JSON:
{
"courts": [
{ "courtId": 1, "name": "Platz 1", "alias": "1", "sortOrder": 1, "inactive": null },
{ "courtId": 2, "name": "Platz 2", "alias": "2", "sortOrder": 2, "inactive": null }
]
}
Die Adresse deines Vereins
Jede Adresse beginnt mit https://my.clubnetz.app/api/Clubs/clubId/. Die Nummer deines Vereins steht in der Adresszeile, wenn du die App verwendest (/clubs/12/my-club), und die Seite „API-Schlüssel“ zeigt ein fertiges Beispiel damit.
Betreibt euer Verein eine eigene Installation von Clubnetz, ersetze my.clubnetz.app durch eure Adresse.
So funktioniert ein Schlüssel
- Er handelt als du
- Ein Schlüssel kann, was der Admin, der ihn erstellt hat, im Verein kann. Änderungen damit werden als von dieser Person gemacht festgehalten.
- Er gilt nur für einen Verein
- Ein Schlüssel ist an den Verein gebunden, in dem er erstellt wurde. Für einen anderen Verein, dein persönliches Profil oder irgendetwas außerhalb von
/api/Clubs/clubId/funktioniert er nicht. - Nur-Lese-Schlüssel lesen nur
- Ein Schlüssel mit „Nur lesen“ darf
GET-Anfragen senden. Alles andere wird mit403beantwortet. - Er endet, wenn du kein Admin mehr bist
- Verlässt die Person, die den Schlüssel erstellt hat, den Verein oder ist sie kein Admin mehr, wird der Schlüssel abgelehnt. Ein anderer Admin erstellt dann einen neuen.
- Er kann keine Schlüssel und kein Stripe-Konto verwalten
- Schlüssel werden nur in der App von einem angemeldeten Admin erstellt und widerrufen, nie mit einem Schlüssel. Dasselbe gilt für das Verbinden und Trennen des Stripe-Kontos des Vereins.
- Jeder Admin kann ihn widerrufen
- Das Widerrufen wirkt sofort und kann nicht rückgängig gemacht werden.
Datenformate
| Was | Format | Beispiel |
|---|---|---|
| Anfragen und Antworten | JSON mit Namen in camelCase. Sende bei einem Inhalt Content-Type: application/json mit. | { "courtId": 1 } |
| Ein Tag | Jahr, Monat, Tag | 2027-06-12 |
| Ein Zeitpunkt | ISO 8601 mit Zeitverschiebung; Antworten sind in UTC | 2027-06-12T16:00:00+00:00 |
| Eine Uhrzeit | Stunden, Minuten, Sekunden in der Ortszeit des Vereins | 18:00:00 |
| Feste Auswahlwerte | Text, keine Zahlen (auf Englisch) | "Social", "Admin" |
| Dateien | Excel-Exporte und Anhänge kommen als Download zurück |
Gib bei Buchungen den Namen deiner Zeitzone als timeZoneInfoId an, zum Beispiel Europe/Vienna.
Beispiele
Die Buchungen einer Woche
curl -H "Authorization: Bearer cnz_DEIN_SCHLUESSEL" \
"https://my.clubnetz.app/api/Clubs/12/Bookings?dayFrom=2027-06-07&dayTo=2027-06-13"
Jede Buchung enthält ihren Platz, ihre Zeit (interval.from und interval.to), die Spielart und die Spieler.
Die Mitgliederliste, Seite für Seite
curl -H "Authorization: Bearer cnz_DEIN_SCHLUESSEL" \
"https://my.clubnetz.app/api/Clubs/12/Members?Page=1&PageSize=50&EnablePaging=true"
Die Antwort enthält total und die Mitglieder der Seite in entities. Filtern kannst du mit SearchTerm, Roles, InSeasonIds und weiteren Parametern, siehe die Referenz unten.
Einen Vereinstermin anlegen
Dafür braucht es einen Schlüssel mit Lesen und schreiben. Die Antwort ist die Id des neuen Termins.
curl -X POST \
-H "Authorization: Bearer cnz_DEIN_SCHLUESSEL" \
-H "Content-Type: application/json" \
-d '{
"title": "Sommerfest",
"category": "Social",
"startDate": "2027-06-12",
"startTime": "18:00:00",
"location": "Clubhaus",
"registrationEnabled": true,
"notifyMembers": false
}' \
https://my.clubnetz.app/api/Clubs/12/ClubEvents
Mit "notifyMembers": true bekommen alle Mitglieder eine Push-Benachrichtigung und eine E-Mail zum neuen Termin. Lass es beim Testen ausgeschaltet.
Python: alle Mitglieder in eine CSV-Datei exportieren
import csv, os, requests
BASE = "https://my.clubnetz.app/api/Clubs/12"
HEADERS = {"Authorization": f"Bearer {os.environ['CLUBNETZ_API_KEY']}"}
members, page = [], 1
while True:
response = requests.get(f"{BASE}/Members", headers=HEADERS,
params={"Page": page, "PageSize": 100, "EnablePaging": "true"})
response.raise_for_status()
data = response.json()
members += data["entities"]
if len(members) >= data["total"] or not data["entities"]:
break
page += 1
with open("mitglieder.csv", "w", newline="", encoding="utf-8") as file:
writer = csv.writer(file)
writer.writerow(["Vorname", "Nachname", "E-Mail", "Rollen"])
for m in members:
writer.writerow([m["firstName"], m["lastName"], m["email"], ", ".join(m["roles"])])
JavaScript (Node.js): die nächsten Vereinstermine
const base = "https://my.clubnetz.app/api/Clubs/12";
const headers = { Authorization: `Bearer ${process.env.CLUBNETZ_API_KEY}` };
const today = new Date().toISOString().slice(0, 10);
const inAMonth = new Date(Date.now() + 30 * 86400000).toISOString().slice(0, 10);
const response = await fetch(`${base}/ClubEvents?from=${today}&to=${inAMonth}`, { headers });
if (!response.ok) throw new Error(`Clubnetz antwortet mit ${response.status}`);
const { events } = await response.json();
for (const event of events) {
console.log(event.startDate, event.startTime ?? "ganztägig", event.title);
}
Lass solche Skripte auf einem Server oder deinem eigenen Computer laufen. Wenn du etwas auf der Vereinswebsite zeigen willst, lass deinen Server die Daten holen und nur das weitergeben, was Besucher sehen sollen. Der Schlüssel gehört nie in die Seite selbst.
Fehler und Limits
| Status | Bedeutung | Was tun |
|---|---|---|
200 | Es hat funktioniert. | |
401 | Der Schlüssel fehlt, ist falsch, abgelaufen, widerrufen, gehört zu einem anderen Verein, oder sein Ersteller ist kein Admin mehr. | Prüfe den Schlüssel und die Vereinsnummer in der Adresse. |
403 | Der Schlüssel darf nur lesen (ApiKeyReadOnly), oder du darfst das nicht. | Verwende einen Schlüssel mit „Lesen und schreiben“. |
404 | Das Angefragte gibt es in deinem Verein nicht. | Prüfe die Id. |
412 | Die Anfrage verletzt eine Regel des Vereins oder enthält ungültige Daten. | Lies errorCode und message in der Antwort. |
429 | Zu viele Anfragen. | Warte so viele Sekunden, wie im Header Retry-After stehen. |
Ein Fehler, der deine Eingabe betrifft, sieht so aus:
{
"message": "A title is required.",
"errorCode": "ClubEventTitleRequired",
"errorDetail": null
}
Verwende in deinem Code errorCode; der Text in message ist englisch und kann sich ändern.
Limit
Jeder Schlüssel darf 120 Anfragen pro Minute senden. Das reicht für Exporte und Anzeigen bei Weitem. Wenn du viele Daten lädst, frage größere Seiten ab, statt viele kleine Anfragen zu senden.
Schlüssel sicher aufbewahren
- Behandle einen Schlüssel wie ein Passwort. Wer ihn hat, kann die Daten eurer Mitglieder lesen.
- Speichere ihn in einer Umgebungsvariable oder einem Secret-Speicher, nicht im Code und nie in einem öffentlichen Repository.
- Er gehört nie in eine Website oder eine Handy-App, wo ihn jeder auslesen kann. Die API beantwortet außerdem keine Anfragen, die ein Browser von einer anderen Website aus sendet.
- Bevorzuge Schlüssel mit „Nur lesen“ und gib Schlüsseln ein Ablaufdatum.
- Könnte ein Schlüssel bekannt geworden sein, widerrufe ihn sofort unter Admin → API-Schlüssel und erstelle einen neuen.
Änderungen an der API
Die App und die API werden gemeinsam veröffentlicht, ein Endpunkt kann sich also mit einer neuen Version von Clubnetz ändern. Jede Antwort enthält die laufende Version im Header X-App-Version. Wenn dir dein Skript wichtig ist, protokolliere diesen Header und prüfe dein Skript nach einem Update. Die Referenz unten beschreibt immer die Version, die gerade läuft.
Referenz der Endpunkte
Alle Endpunkte, die ein Schlüssel aufrufen kann, live aus dem OpenAPI-Dokument von Clubnetz geladen. Die Pfade sind ohne das führende /api/Clubs/clubId angegeben. Namen und Beschreibungen in der Referenz sind englisch.
OpenAPI-Dokument herunterladen
Diese Datei kannst du in Werkzeuge wie Postman, Insomnia oder Bruno importieren oder daraus einen Client für deine Programmiersprache erzeugen.