Clubnetz

Documentation

Clubnetz API

Connect your own scripts and tools to your club. Everything the app can do for a club admin is available over HTTP with an API key: bookings, members, seasons, events, news, court blockings and more.

What you can build

The API is meant for club admins who know a little programming and want to save themselves recurring work. Some ideas:

  • Show today's free courts or the next club events on your club website.
  • Export the member list to a spreadsheet or your accounting tool every night.
  • Create the court blockings for the whole team championship from a list of dates.
  • Post the bookings of the day to a display in the clubhouse.
  • Publish a news item automatically when your league results come in.

There is no separate "public API" with fewer features: a key uses the same endpoints as the Clubnetz app itself.

Create an API key

  1. Log in to Clubnetz as an admin of your club.
  2. Open Admin → API keys in the menu.
  3. Choose New key, give it a name that says what it is for, and pick how long it is valid.
  4. Decide what it may do: Read only for exports and displays, Read and write if it should change something.
  5. Copy the key. It starts with cnz_ and is shown only once.

Use one key per script or tool. Then you can see which one was used last and revoke a single key without breaking the others.

Your first request

Send the key in the Authorization header. This lists the courts of your club:

curl -H "Authorization: Bearer cnz_YOUR_KEY" \
  https://my.clubnetz.app/api/Clubs/12/Courts

The answer is JSON:

{
  "courts": [
    { "courtId": 1, "name": "Court 1", "alias": "1", "sortOrder": 1, "inactive": null },
    { "courtId": 2, "name": "Court 2", "alias": "2", "sortOrder": 2, "inactive": null }
  ]
}

The address of your club

Every address starts with https://my.clubnetz.app/api/Clubs/clubId/. The number of your club is in the address bar when you use the app (/clubs/12/my-club), and the API keys page shows a ready-made example with it.

If your club runs its own installation of Clubnetz, replace my.clubnetz.app with your own address.

How a key works

It acts as you
A key can do what the admin who created it can do in the club. Changes made with it are recorded as made by that person.
It only works for one club
A key is bound to the club it was created in. It can't be used for another club, your personal profile or anything outside /api/Clubs/clubId/.
Read-only keys only read
A read-only key may send GET requests. Everything else is answered with 403.
It stops when you stop being admin
If the person who created the key leaves the club or is no longer an admin, the key is rejected. Another admin then creates a new one.
It can't manage keys or the Stripe account
Keys are only created and revoked in the app by a logged-in admin, never with a key. The same goes for connecting and disconnecting the club's Stripe account.
Every admin can revoke it
Revoking takes effect immediately and can't be undone.

Data formats

WhatFormatExample
Requests and answersJSON with camelCase names. Send Content-Type: application/json with a body.{ "courtId": 1 }
A dayYear, month, day2027-06-12
A point in timeISO 8601 with offset; answers are in UTC2027-06-12T16:00:00+00:00
A time of dayHours, minutes, seconds in the club's local time18:00:00
Fixed choicesText, not numbers"Social", "Admin"
FilesExcel exports and attachments are returned as a download

For bookings, pass the name of your time zone as timeZoneInfoId, for example Europe/Vienna.

Examples

The bookings of a week

curl -H "Authorization: Bearer cnz_YOUR_KEY" \
  "https://my.clubnetz.app/api/Clubs/12/Bookings?dayFrom=2027-06-07&dayTo=2027-06-13"

Each booking has its court, its time (interval.from and interval.to), the play mode and the players.

The member list, page by page

curl -H "Authorization: Bearer cnz_YOUR_KEY" \
  "https://my.clubnetz.app/api/Clubs/12/Members?Page=1&PageSize=50&EnablePaging=true"

The answer contains total and the members of the page in entities. You can filter with SearchTerm, Roles, InSeasonIds and more, see the reference below.

Create a club event

This needs a key with Read and write. The answer is the id of the new event.

curl -X POST \
  -H "Authorization: Bearer cnz_YOUR_KEY" \
  -H "Content-Type: application/json" \
  -d '{
        "title": "Summer party",
        "category": "Social",
        "startDate": "2027-06-12",
        "startTime": "18:00:00",
        "location": "Clubhouse",
        "registrationEnabled": true,
        "notifyMembers": false
      }' \
  https://my.clubnetz.app/api/Clubs/12/ClubEvents

With "notifyMembers": true all members get a push notification and an email about the new event. Leave it off while you are testing.

Python: export all members to a CSV file

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("members.csv", "w", newline="", encoding="utf-8") as file:
    writer = csv.writer(file)
    writer.writerow(["First name", "Last name", "Email", "Roles"])
    for m in members:
        writer.writerow([m["firstName"], m["lastName"], m["email"], ", ".join(m["roles"])])

JavaScript (Node.js): the next club events

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 answered ${response.status}`);

const { events } = await response.json();
for (const event of events) {
    console.log(event.startDate, event.startTime ?? "all day", event.title);
}

Run such scripts on a server or your own computer. If you want to show something on your club website, let your server fetch the data and pass on only what visitors should see. Never put the key into the page itself.

Errors and limits

StatusMeaningWhat to do
200It worked.
401The key is missing, wrong, expired, revoked, belongs to another club, or its creator is no longer an admin.Check the key and the club number in the address.
403The key is read-only (ApiKeyReadOnly), or you are not allowed to do this.Use a key with read and write access.
404What you asked for does not exist in your club.Check the id.
412The request breaks a rule of the club or contains invalid data.Read errorCode and message in the answer.
429Too many requests.Wait for the number of seconds in the Retry-After header.

An error that concerns your input looks like this:

{
  "message": "A title is required.",
  "errorCode": "ClubEventTitleRequired",
  "errorDetail": null
}

Use errorCode in your code; the text of message may change.

Limit

Each key may send 120 requests per minute. That is plenty for exports and displays. If you load a lot of data, ask for larger pages instead of sending many small requests.

Keeping keys safe

  • Treat a key like a password. Whoever has it can read the data of your members.
  • Store it in an environment variable or a secrets store, not in the code and never in a public repository.
  • Never put it into a website or a mobile app, where everybody can read it. The API also does not answer requests that a browser sends from another website.
  • Prefer read-only keys and give keys an expiry date.
  • If a key may have leaked, revoke it right away under Admin → API keys and create a new one.

Changes to the API

The app and the API are released together, so an endpoint can change with a new version of Clubnetz. Every answer carries the running version in the X-App-Version header. If your script matters to you, log that header and check your script after an update. The reference below always describes the version that is running right now.

Endpoint reference

All endpoints a key can call, loaded live from the OpenAPI document of Clubnetz. Paths are shown without the leading /api/Clubs/clubId.

Download the OpenAPI document

You can import this file into tools such as Postman, Insomnia or Bruno, or generate a client for your programming language from it.

Is something missing?

Tell us what you want to build, or open an issue on GitHub. Clubnetz is open source, so you can also add it yourself.

hello@clubnetz.app