{
  "openapi": "3.1.0",
  "info": {
    "title": "CLUP.life Schnittstelle",
    "version": "1.0.0",
    "description": "Öffentliche REST-Schnittstelle für Mitglieder, Vereine, Verbände und Kommunen. Authentifizierung mit API-Schlüssel (Bearer). Ein Schlüssel handelt immer als die Person, die ihn angelegt hat: Rollen, Sichtbarkeit und Kinderrechte gelten unverändert; Bereiche machen ihn nur enger. Grenzen: Basis 60 Anfragen/Minute je Schlüssel, Premium 600. Listen nutzen Cursor-Seiten. Webhooks: event.created, event.updated, event.cancelled, member.joined, member.left, post.created, announcement.created, task.created, presse.veroeffentlicht (dünne Ereignisse, signiert mit X-Clup-Signature). MCP: POST /api/v1/ext/mcp (JSON-RPC, Streamable HTTP). Handbuch: docs/SCHNITTSTELLEN.md.",
    "contact": {
      "name": "CLUP.life Support"
    }
  },
  "servers": [
    {
      "url": "https://api.clup.life/api/v1"
    }
  ],
  "paths": {
    "/ext/me": {
      "get": {
        "summary": "Wer bin ich? Konto, Bereiche des Schlüssels, Mitgliedschaften",
        "description": "Benötigte Bereiche: profile:read. Die Rechte der Person hinter dem Schlüssel gelten unverändert; fremde oder nicht sichtbare Organisationen antworten 404.",
        "security": [
          {
            "apiKey": [
              "profile:read"
            ]
          }
        ],
        "parameters": [],
        "responses": {
          "200": {
            "description": "Erfolg"
          },
          "401": {
            "description": "Schlüssel ungültig, abgelaufen oder widerrufen (INVALID_API_KEY)"
          },
          "403": {
            "description": "Bereich fehlt (INSUFFICIENT_SCOPE), Recht fehlt (FORBIDDEN) oder Premium nötig (PREMIUM_REQUIRED)"
          },
          "404": {
            "description": "Nicht gefunden — auch für Organisationen, die der Schlüssel nicht sehen darf"
          },
          "429": {
            "description": "Zu viele Anfragen (RATE_LIMITED); Retry-After beachten"
          }
        },
        "x-codeSamples": [
          {
            "lang": "Shell",
            "label": "curl",
            "source": "curl -H \"Authorization: Bearer clup_k_…\" \"https://api.clup.life/api/v1/ext/me\""
          }
        ]
      }
    },
    "/ext/directory/organizations": {
      "get": {
        "summary": "Vereinsverzeichnis durchsuchen (nur öffentliche Organisationen)",
        "description": "Benötigte Bereiche: directory:read. Die Rechte der Person hinter dem Schlüssel gelten unverändert; fremde oder nicht sichtbare Organisationen antworten 404.",
        "security": [
          {
            "apiKey": [
              "directory:read"
            ]
          }
        ],
        "parameters": [
          {
            "name": "cursor",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Fortsetzung aus nextCursor der vorigen Antwort (keine Seitenzahlen, kein OFFSET)"
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "1–100, Standard 30"
          },
          {
            "name": "q",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Name, Kurzname oder Ort"
          },
          {
            "name": "categories",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Themen, getrennt mit |"
          },
          {
            "name": "types",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "CLUB, ASSOCIATION, GROUP, MUNICIPALITY (kommagetrennt)"
          },
          {
            "name": "state",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Bundesland als Code, z. B. DE-RP (kommagetrennt)"
          },
          {
            "name": "place",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Ort oder Postleitzahl"
          },
          {
            "name": "radiusKm",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Umkreis 1–300 (mit place)"
          },
          {
            "name": "ageFrom",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Angebot für Alter von"
          },
          {
            "name": "ageTo",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Angebot für Alter bis"
          },
          {
            "name": "membersMin",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Mindestzahl Mitglieder"
          },
          {
            "name": "membersMax",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Höchstzahl Mitglieder"
          },
          {
            "name": "foundedFrom",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Gegründet ab (Jahr)"
          },
          {
            "name": "foundedTo",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Gegründet bis (Jahr)"
          },
          {
            "name": "accepting",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "1 = nimmt neue Mitglieder auf"
          },
          {
            "name": "sort",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "relevance, distance, name, size oder new"
          }
        ],
        "responses": {
          "200": {
            "description": "Erfolg"
          },
          "401": {
            "description": "Schlüssel ungültig, abgelaufen oder widerrufen (INVALID_API_KEY)"
          },
          "403": {
            "description": "Bereich fehlt (INSUFFICIENT_SCOPE), Recht fehlt (FORBIDDEN) oder Premium nötig (PREMIUM_REQUIRED)"
          },
          "404": {
            "description": "Nicht gefunden — auch für Organisationen, die der Schlüssel nicht sehen darf"
          },
          "429": {
            "description": "Zu viele Anfragen (RATE_LIMITED); Retry-After beachten"
          }
        },
        "x-codeSamples": [
          {
            "lang": "Shell",
            "label": "curl",
            "source": "curl -H \"Authorization: Bearer clup_k_…\" \"https://api.clup.life/api/v1/ext/directory/organizations\""
          }
        ]
      }
    },
    "/ext/events": {
      "get": {
        "summary": "Termine eines Zeitraums",
        "description": "Benötigte Bereiche: events:read. Die Rechte der Person hinter dem Schlüssel gelten unverändert; fremde oder nicht sichtbare Organisationen antworten 404.",
        "security": [
          {
            "apiKey": [
              "events:read"
            ]
          }
        ],
        "parameters": [
          {
            "name": "from",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Beginn des Zeitraums (ISO 8601, z. B. 2026-11-01T00:00:00Z)"
          },
          {
            "name": "to",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Ende des Zeitraums (höchstens 400 Tage nach from)"
          },
          {
            "name": "organization",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Nur Termine dieser Organisation (slug)"
          }
        ],
        "responses": {
          "200": {
            "description": "Erfolg"
          },
          "401": {
            "description": "Schlüssel ungültig, abgelaufen oder widerrufen (INVALID_API_KEY)"
          },
          "403": {
            "description": "Bereich fehlt (INSUFFICIENT_SCOPE), Recht fehlt (FORBIDDEN) oder Premium nötig (PREMIUM_REQUIRED)"
          },
          "404": {
            "description": "Nicht gefunden — auch für Organisationen, die der Schlüssel nicht sehen darf"
          },
          "429": {
            "description": "Zu viele Anfragen (RATE_LIMITED); Retry-After beachten"
          }
        },
        "x-codeSamples": [
          {
            "lang": "Shell",
            "label": "curl",
            "source": "curl -H \"Authorization: Bearer clup_k_…\" \"https://api.clup.life/api/v1/ext/events?from=2026-11-01T00:00:00Z&to=2026-12-01T00:00:00Z\""
          }
        ]
      }
    },
    "/ext/organizations/{org}/events": {
      "post": {
        "summary": "Termin anlegen",
        "description": "Benötigte Bereiche: events:write. Nur mit Schlüssel einer Organisation mit Premium. Die Rechte der Person hinter dem Schlüssel gelten unverändert; fremde oder nicht sichtbare Organisationen antworten 404.",
        "security": [
          {
            "apiKey": [
              "events:write"
            ]
          }
        ],
        "parameters": [
          {
            "name": "org",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Kennung (slug) der Organisation"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object"
              },
              "example": {
                "title": "Sommerfest",
                "startsAt": "2026-07-04T14:00:00Z",
                "endsAt": "2026-07-04T20:00:00Z",
                "visibility": "MEMBERS"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Erfolg"
          },
          "401": {
            "description": "Schlüssel ungültig, abgelaufen oder widerrufen (INVALID_API_KEY)"
          },
          "403": {
            "description": "Bereich fehlt (INSUFFICIENT_SCOPE), Recht fehlt (FORBIDDEN) oder Premium nötig (PREMIUM_REQUIRED)"
          },
          "404": {
            "description": "Nicht gefunden — auch für Organisationen, die der Schlüssel nicht sehen darf"
          },
          "429": {
            "description": "Zu viele Anfragen (RATE_LIMITED); Retry-After beachten"
          }
        },
        "x-codeSamples": [
          {
            "lang": "Shell",
            "label": "curl",
            "source": "curl -X POST -H \"Authorization: Bearer clup_k_…\" -H \"Content-Type: application/json\" -d '{\"title\":\"Sommerfest\",\"startsAt\":\"2026-07-04T14:00:00Z\",\"endsAt\":\"2026-07-04T20:00:00Z\",\"visibility\":\"MEMBERS\"}' \"https://api.clup.life/api/v1/ext/organizations/mein-verein/events\""
          }
        ]
      }
    },
    "/ext/organizations/{org}/members": {
      "get": {
        "summary": "Mitgliederliste (nur wenn die Rolle der Person sie zeigt)",
        "description": "Benötigte Bereiche: members:read. Die Rechte der Person hinter dem Schlüssel gelten unverändert; fremde oder nicht sichtbare Organisationen antworten 404.",
        "security": [
          {
            "apiKey": [
              "members:read"
            ]
          }
        ],
        "parameters": [
          {
            "name": "org",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Kennung (slug) der Organisation"
          },
          {
            "name": "cursor",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Fortsetzung aus nextCursor der vorigen Antwort (keine Seitenzahlen, kein OFFSET)"
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "1–100, Standard 30"
          },
          {
            "name": "q",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Suche im Anzeigenamen"
          }
        ],
        "responses": {
          "200": {
            "description": "Erfolg"
          },
          "401": {
            "description": "Schlüssel ungültig, abgelaufen oder widerrufen (INVALID_API_KEY)"
          },
          "403": {
            "description": "Bereich fehlt (INSUFFICIENT_SCOPE), Recht fehlt (FORBIDDEN) oder Premium nötig (PREMIUM_REQUIRED)"
          },
          "404": {
            "description": "Nicht gefunden — auch für Organisationen, die der Schlüssel nicht sehen darf"
          },
          "429": {
            "description": "Zu viele Anfragen (RATE_LIMITED); Retry-After beachten"
          }
        },
        "x-codeSamples": [
          {
            "lang": "Shell",
            "label": "curl",
            "source": "curl -H \"Authorization: Bearer clup_k_…\" \"https://api.clup.life/api/v1/ext/organizations/mein-verein/members\""
          }
        ]
      }
    },
    "/ext/organizations/{org}/posts": {
      "get": {
        "summary": "Beiträge",
        "description": "Benötigte Bereiche: posts:read. Die Rechte der Person hinter dem Schlüssel gelten unverändert; fremde oder nicht sichtbare Organisationen antworten 404.",
        "security": [
          {
            "apiKey": [
              "posts:read"
            ]
          }
        ],
        "parameters": [
          {
            "name": "org",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Kennung (slug) der Organisation"
          },
          {
            "name": "cursor",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Fortsetzung aus nextCursor der vorigen Antwort (keine Seitenzahlen, kein OFFSET)"
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "1–100, Standard 30"
          }
        ],
        "responses": {
          "200": {
            "description": "Erfolg"
          },
          "401": {
            "description": "Schlüssel ungültig, abgelaufen oder widerrufen (INVALID_API_KEY)"
          },
          "403": {
            "description": "Bereich fehlt (INSUFFICIENT_SCOPE), Recht fehlt (FORBIDDEN) oder Premium nötig (PREMIUM_REQUIRED)"
          },
          "404": {
            "description": "Nicht gefunden — auch für Organisationen, die der Schlüssel nicht sehen darf"
          },
          "429": {
            "description": "Zu viele Anfragen (RATE_LIMITED); Retry-After beachten"
          }
        },
        "x-codeSamples": [
          {
            "lang": "Shell",
            "label": "curl",
            "source": "curl -H \"Authorization: Bearer clup_k_…\" \"https://api.clup.life/api/v1/ext/organizations/mein-verein/posts\""
          }
        ]
      }
    },
    "/ext/organizations/{org}/announcements": {
      "get": {
        "summary": "Mitteilungen",
        "description": "Benötigte Bereiche: announcements:read. Die Rechte der Person hinter dem Schlüssel gelten unverändert; fremde oder nicht sichtbare Organisationen antworten 404.",
        "security": [
          {
            "apiKey": [
              "announcements:read"
            ]
          }
        ],
        "parameters": [
          {
            "name": "org",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Kennung (slug) der Organisation"
          },
          {
            "name": "cursor",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Fortsetzung aus nextCursor der vorigen Antwort (keine Seitenzahlen, kein OFFSET)"
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "1–100, Standard 30"
          }
        ],
        "responses": {
          "200": {
            "description": "Erfolg"
          },
          "401": {
            "description": "Schlüssel ungültig, abgelaufen oder widerrufen (INVALID_API_KEY)"
          },
          "403": {
            "description": "Bereich fehlt (INSUFFICIENT_SCOPE), Recht fehlt (FORBIDDEN) oder Premium nötig (PREMIUM_REQUIRED)"
          },
          "404": {
            "description": "Nicht gefunden — auch für Organisationen, die der Schlüssel nicht sehen darf"
          },
          "429": {
            "description": "Zu viele Anfragen (RATE_LIMITED); Retry-After beachten"
          }
        },
        "x-codeSamples": [
          {
            "lang": "Shell",
            "label": "curl",
            "source": "curl -H \"Authorization: Bearer clup_k_…\" \"https://api.clup.life/api/v1/ext/organizations/mein-verein/announcements\""
          }
        ]
      },
      "post": {
        "summary": "Mitteilung veröffentlichen",
        "description": "Benötigte Bereiche: announcements:write. Nur mit Schlüssel einer Organisation mit Premium. Die Rechte der Person hinter dem Schlüssel gelten unverändert; fremde oder nicht sichtbare Organisationen antworten 404.",
        "security": [
          {
            "apiKey": [
              "announcements:write"
            ]
          }
        ],
        "parameters": [
          {
            "name": "org",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Kennung (slug) der Organisation"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object"
              },
              "example": {
                "title": "Hallenzeiten ändern sich",
                "body": "Ab Montag trainieren wir in der kleinen Halle."
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Erfolg"
          },
          "401": {
            "description": "Schlüssel ungültig, abgelaufen oder widerrufen (INVALID_API_KEY)"
          },
          "403": {
            "description": "Bereich fehlt (INSUFFICIENT_SCOPE), Recht fehlt (FORBIDDEN) oder Premium nötig (PREMIUM_REQUIRED)"
          },
          "404": {
            "description": "Nicht gefunden — auch für Organisationen, die der Schlüssel nicht sehen darf"
          },
          "429": {
            "description": "Zu viele Anfragen (RATE_LIMITED); Retry-After beachten"
          }
        },
        "x-codeSamples": [
          {
            "lang": "Shell",
            "label": "curl",
            "source": "curl -X POST -H \"Authorization: Bearer clup_k_…\" -H \"Content-Type: application/json\" -d '{\"title\":\"Hallenzeiten ändern sich\",\"body\":\"Ab Montag trainieren wir in der kleinen Halle.\"}' \"https://api.clup.life/api/v1/ext/organizations/mein-verein/announcements\""
          }
        ]
      }
    },
    "/ext/organizations/{org}/tasks": {
      "get": {
        "summary": "Aufgaben",
        "description": "Benötigte Bereiche: tasks:read. Die Rechte der Person hinter dem Schlüssel gelten unverändert; fremde oder nicht sichtbare Organisationen antworten 404.",
        "security": [
          {
            "apiKey": [
              "tasks:read"
            ]
          }
        ],
        "parameters": [
          {
            "name": "org",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Kennung (slug) der Organisation"
          },
          {
            "name": "scope",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "open (Standard) oder done"
          },
          {
            "name": "cursor",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Fortsetzung aus nextCursor der vorigen Antwort (keine Seitenzahlen, kein OFFSET)"
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "1–100, Standard 30"
          }
        ],
        "responses": {
          "200": {
            "description": "Erfolg"
          },
          "401": {
            "description": "Schlüssel ungültig, abgelaufen oder widerrufen (INVALID_API_KEY)"
          },
          "403": {
            "description": "Bereich fehlt (INSUFFICIENT_SCOPE), Recht fehlt (FORBIDDEN) oder Premium nötig (PREMIUM_REQUIRED)"
          },
          "404": {
            "description": "Nicht gefunden — auch für Organisationen, die der Schlüssel nicht sehen darf"
          },
          "429": {
            "description": "Zu viele Anfragen (RATE_LIMITED); Retry-After beachten"
          }
        },
        "x-codeSamples": [
          {
            "lang": "Shell",
            "label": "curl",
            "source": "curl -H \"Authorization: Bearer clup_k_…\" \"https://api.clup.life/api/v1/ext/organizations/mein-verein/tasks\""
          }
        ]
      },
      "post": {
        "summary": "Aufgabe anlegen",
        "description": "Benötigte Bereiche: tasks:write. Nur mit Schlüssel einer Organisation mit Premium. Die Rechte der Person hinter dem Schlüssel gelten unverändert; fremde oder nicht sichtbare Organisationen antworten 404.",
        "security": [
          {
            "apiKey": [
              "tasks:write"
            ]
          }
        ],
        "parameters": [
          {
            "name": "org",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Kennung (slug) der Organisation"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object"
              },
              "example": {
                "title": "Zelte prüfen",
                "dueDate": "2026-06-20"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Erfolg"
          },
          "401": {
            "description": "Schlüssel ungültig, abgelaufen oder widerrufen (INVALID_API_KEY)"
          },
          "403": {
            "description": "Bereich fehlt (INSUFFICIENT_SCOPE), Recht fehlt (FORBIDDEN) oder Premium nötig (PREMIUM_REQUIRED)"
          },
          "404": {
            "description": "Nicht gefunden — auch für Organisationen, die der Schlüssel nicht sehen darf"
          },
          "429": {
            "description": "Zu viele Anfragen (RATE_LIMITED); Retry-After beachten"
          }
        },
        "x-codeSamples": [
          {
            "lang": "Shell",
            "label": "curl",
            "source": "curl -X POST -H \"Authorization: Bearer clup_k_…\" -H \"Content-Type: application/json\" -d '{\"title\":\"Zelte prüfen\",\"dueDate\":\"2026-06-20\"}' \"https://api.clup.life/api/v1/ext/organizations/mein-verein/tasks\""
          }
        ]
      }
    },
    "/ext/presse/posts": {
      "get": {
        "summary": "Veröffentlichte Pressemeldungen und News",
        "description": "Benötigte Bereiche: presse:read. Die Rechte der Person hinter dem Schlüssel gelten unverändert; fremde oder nicht sichtbare Organisationen antworten 404.",
        "security": [
          {
            "apiKey": [
              "presse:read"
            ]
          }
        ],
        "parameters": [
          {
            "name": "art",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "PRESS_RELEASE oder NEWS"
          },
          {
            "name": "lang",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Sprachcode, z. B. de, en (Rückfall Deutsch)"
          },
          {
            "name": "cursor",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Fortsetzung aus nextCursor der vorigen Antwort (keine Seitenzahlen, kein OFFSET)"
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "1–100, Standard 30"
          }
        ],
        "responses": {
          "200": {
            "description": "Erfolg"
          },
          "401": {
            "description": "Schlüssel ungültig, abgelaufen oder widerrufen (INVALID_API_KEY)"
          },
          "403": {
            "description": "Bereich fehlt (INSUFFICIENT_SCOPE), Recht fehlt (FORBIDDEN) oder Premium nötig (PREMIUM_REQUIRED)"
          },
          "404": {
            "description": "Nicht gefunden — auch für Organisationen, die der Schlüssel nicht sehen darf"
          },
          "429": {
            "description": "Zu viele Anfragen (RATE_LIMITED); Retry-After beachten"
          }
        },
        "x-codeSamples": [
          {
            "lang": "Shell",
            "label": "curl",
            "source": "curl -H \"Authorization: Bearer clup_k_…\" \"https://api.clup.life/api/v1/ext/presse/posts\""
          }
        ]
      },
      "post": {
        "summary": "Pressemeldung oder News als Entwurf anlegen",
        "description": "Benötigte Bereiche: presse:write. Nur mit Schlüssel der Plattform-Organisation und Plattformrecht Presse (kein Premium nötig). Die Rechte der Person hinter dem Schlüssel gelten unverändert; fremde oder nicht sichtbare Organisationen antworten 404.",
        "security": [
          {
            "apiKey": [
              "presse:write"
            ]
          }
        ],
        "parameters": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object"
              },
              "example": {
                "kind": "NEWS",
                "slug": "neue-funktion",
                "texts": [
                  {
                    "locale": "de",
                    "title": "Neue Funktion",
                    "summary": "Kurzer Anreißer der Meldung.",
                    "body": "Text in einfachem Markdown."
                  }
                ]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Erfolg"
          },
          "401": {
            "description": "Schlüssel ungültig, abgelaufen oder widerrufen (INVALID_API_KEY)"
          },
          "403": {
            "description": "Bereich fehlt (INSUFFICIENT_SCOPE), Recht fehlt (FORBIDDEN) oder Premium nötig (PREMIUM_REQUIRED)"
          },
          "404": {
            "description": "Nicht gefunden — auch für Organisationen, die der Schlüssel nicht sehen darf"
          },
          "429": {
            "description": "Zu viele Anfragen (RATE_LIMITED); Retry-After beachten"
          }
        },
        "x-codeSamples": [
          {
            "lang": "Shell",
            "label": "curl",
            "source": "curl -X POST -H \"Authorization: Bearer clup_k_…\" -H \"Content-Type: application/json\" -d '{\"kind\":\"NEWS\",\"slug\":\"neue-funktion\",\"texts\":[{\"locale\":\"de\",\"title\":\"Neue Funktion\",\"summary\":\"Kurzer Anreißer der Meldung.\",\"body\":\"Text in einfachem Markdown.\"}]}' \"https://api.clup.life/api/v1/ext/presse/posts\""
          }
        ]
      }
    },
    "/ext/presse/posts/{ref}": {
      "get": {
        "summary": "Ein Beitrag per slug (mit presse:write auch per Kennung, inkl. Entwurf)",
        "description": "Benötigte Bereiche: presse:read. Die Rechte der Person hinter dem Schlüssel gelten unverändert; fremde oder nicht sichtbare Organisationen antworten 404.",
        "security": [
          {
            "apiKey": [
              "presse:read"
            ]
          }
        ],
        "parameters": [
          {
            "name": "ref",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "slug oder Kennung des Beitrags"
          },
          {
            "name": "lang",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Sprachcode, z. B. de, en (Rückfall Deutsch)"
          }
        ],
        "responses": {
          "200": {
            "description": "Erfolg"
          },
          "401": {
            "description": "Schlüssel ungültig, abgelaufen oder widerrufen (INVALID_API_KEY)"
          },
          "403": {
            "description": "Bereich fehlt (INSUFFICIENT_SCOPE), Recht fehlt (FORBIDDEN) oder Premium nötig (PREMIUM_REQUIRED)"
          },
          "404": {
            "description": "Nicht gefunden — auch für Organisationen, die der Schlüssel nicht sehen darf"
          },
          "429": {
            "description": "Zu viele Anfragen (RATE_LIMITED); Retry-After beachten"
          }
        },
        "x-codeSamples": [
          {
            "lang": "Shell",
            "label": "curl",
            "source": "curl -H \"Authorization: Bearer clup_k_…\" \"https://api.clup.life/api/v1/ext/presse/posts/go-live\""
          }
        ]
      }
    },
    "/ext/presse/posts/{id}": {
      "put": {
        "summary": "Beitrag ändern",
        "description": "Benötigte Bereiche: presse:write. Nur mit Schlüssel der Plattform-Organisation und Plattformrecht Presse (kein Premium nötig). Die Rechte der Person hinter dem Schlüssel gelten unverändert; fremde oder nicht sichtbare Organisationen antworten 404.",
        "security": [
          {
            "apiKey": [
              "presse:write"
            ]
          }
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Kennung des Beitrags"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object"
              },
              "example": {
                "kind": "NEWS",
                "slug": "neue-funktion",
                "texts": [
                  {
                    "locale": "de",
                    "title": "Neue Funktion",
                    "summary": "Kurzer Anreißer der Meldung.",
                    "body": "Geänderter Text."
                  }
                ]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Erfolg"
          },
          "401": {
            "description": "Schlüssel ungültig, abgelaufen oder widerrufen (INVALID_API_KEY)"
          },
          "403": {
            "description": "Bereich fehlt (INSUFFICIENT_SCOPE), Recht fehlt (FORBIDDEN) oder Premium nötig (PREMIUM_REQUIRED)"
          },
          "404": {
            "description": "Nicht gefunden — auch für Organisationen, die der Schlüssel nicht sehen darf"
          },
          "429": {
            "description": "Zu viele Anfragen (RATE_LIMITED); Retry-After beachten"
          }
        },
        "x-codeSamples": [
          {
            "lang": "Shell",
            "label": "curl",
            "source": "curl -X PUT -H \"Authorization: Bearer clup_k_…\" -H \"Content-Type: application/json\" -d '{\"kind\":\"NEWS\",\"slug\":\"neue-funktion\",\"texts\":[{\"locale\":\"de\",\"title\":\"Neue Funktion\",\"summary\":\"Kurzer Anreißer der Meldung.\",\"body\":\"Geänderter Text.\"}]}' \"https://api.clup.life/api/v1/ext/presse/posts/BEITRAGS-ID\""
          }
        ]
      }
    },
    "/ext/presse/posts/{id}/publish": {
      "post": {
        "summary": "Beitrag jetzt veröffentlichen",
        "description": "Benötigte Bereiche: presse:write. Nur mit Schlüssel der Plattform-Organisation und Plattformrecht Presse (kein Premium nötig). Die Rechte der Person hinter dem Schlüssel gelten unverändert; fremde oder nicht sichtbare Organisationen antworten 404.",
        "security": [
          {
            "apiKey": [
              "presse:write"
            ]
          }
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Kennung des Beitrags"
          }
        ],
        "responses": {
          "200": {
            "description": "Erfolg"
          },
          "401": {
            "description": "Schlüssel ungültig, abgelaufen oder widerrufen (INVALID_API_KEY)"
          },
          "403": {
            "description": "Bereich fehlt (INSUFFICIENT_SCOPE), Recht fehlt (FORBIDDEN) oder Premium nötig (PREMIUM_REQUIRED)"
          },
          "404": {
            "description": "Nicht gefunden — auch für Organisationen, die der Schlüssel nicht sehen darf"
          },
          "429": {
            "description": "Zu viele Anfragen (RATE_LIMITED); Retry-After beachten"
          }
        },
        "x-codeSamples": [
          {
            "lang": "Shell",
            "label": "curl",
            "source": "curl -X POST -H \"Authorization: Bearer clup_k_…\" \"https://api.clup.life/api/v1/ext/presse/posts/BEITRAGS-ID/publish\""
          }
        ]
      }
    },
    "/ext/presse/posts/{id}/schedule": {
      "post": {
        "summary": "Veröffentlichung planen",
        "description": "Benötigte Bereiche: presse:write. Nur mit Schlüssel der Plattform-Organisation und Plattformrecht Presse (kein Premium nötig). Die Rechte der Person hinter dem Schlüssel gelten unverändert; fremde oder nicht sichtbare Organisationen antworten 404.",
        "security": [
          {
            "apiKey": [
              "presse:write"
            ]
          }
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Kennung des Beitrags"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object"
              },
              "example": {
                "publishAt": "2026-11-01T08:00:00Z"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Erfolg"
          },
          "401": {
            "description": "Schlüssel ungültig, abgelaufen oder widerrufen (INVALID_API_KEY)"
          },
          "403": {
            "description": "Bereich fehlt (INSUFFICIENT_SCOPE), Recht fehlt (FORBIDDEN) oder Premium nötig (PREMIUM_REQUIRED)"
          },
          "404": {
            "description": "Nicht gefunden — auch für Organisationen, die der Schlüssel nicht sehen darf"
          },
          "429": {
            "description": "Zu viele Anfragen (RATE_LIMITED); Retry-After beachten"
          }
        },
        "x-codeSamples": [
          {
            "lang": "Shell",
            "label": "curl",
            "source": "curl -X POST -H \"Authorization: Bearer clup_k_…\" -H \"Content-Type: application/json\" -d '{\"publishAt\":\"2026-11-01T08:00:00Z\"}' \"https://api.clup.life/api/v1/ext/presse/posts/BEITRAGS-ID/schedule\""
          }
        ]
      }
    },
    "/ext/exports/events.ics": {
      "get": {
        "summary": "Termine als iCal",
        "description": "Benötigte Bereiche: exports:read. Die Rechte der Person hinter dem Schlüssel gelten unverändert; fremde oder nicht sichtbare Organisationen antworten 404.",
        "security": [
          {
            "apiKey": [
              "exports:read"
            ]
          }
        ],
        "parameters": [
          {
            "name": "from",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Beginn des Zeitraums (ISO 8601, z. B. 2026-11-01T00:00:00Z)"
          },
          {
            "name": "to",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Ende des Zeitraums (höchstens 400 Tage nach from)"
          },
          {
            "name": "organization",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Nur Termine dieser Organisation (slug)"
          }
        ],
        "responses": {
          "200": {
            "description": "Erfolg",
            "content": {
              "text/calendar": {
                "schema": {
                  "type": "string"
                }
              }
            }
          },
          "401": {
            "description": "Schlüssel ungültig, abgelaufen oder widerrufen (INVALID_API_KEY)"
          },
          "403": {
            "description": "Bereich fehlt (INSUFFICIENT_SCOPE), Recht fehlt (FORBIDDEN) oder Premium nötig (PREMIUM_REQUIRED)"
          },
          "404": {
            "description": "Nicht gefunden — auch für Organisationen, die der Schlüssel nicht sehen darf"
          },
          "429": {
            "description": "Zu viele Anfragen (RATE_LIMITED); Retry-After beachten"
          }
        },
        "x-codeSamples": [
          {
            "lang": "Shell",
            "label": "curl",
            "source": "curl -H \"Authorization: Bearer clup_k_…\" \"https://api.clup.life/api/v1/ext/exports/events.ics?from=2026-11-01T00:00:00Z&to=2026-12-01T00:00:00Z\""
          }
        ]
      }
    },
    "/ext/exports/events.csv": {
      "get": {
        "summary": "Termine als CSV",
        "description": "Benötigte Bereiche: exports:read. Die Rechte der Person hinter dem Schlüssel gelten unverändert; fremde oder nicht sichtbare Organisationen antworten 404.",
        "security": [
          {
            "apiKey": [
              "exports:read"
            ]
          }
        ],
        "parameters": [
          {
            "name": "from",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Beginn des Zeitraums (ISO 8601, z. B. 2026-11-01T00:00:00Z)"
          },
          {
            "name": "to",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Ende des Zeitraums (höchstens 400 Tage nach from)"
          },
          {
            "name": "organization",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Nur Termine dieser Organisation (slug)"
          }
        ],
        "responses": {
          "200": {
            "description": "Erfolg",
            "content": {
              "text/csv": {
                "schema": {
                  "type": "string"
                }
              }
            }
          },
          "401": {
            "description": "Schlüssel ungültig, abgelaufen oder widerrufen (INVALID_API_KEY)"
          },
          "403": {
            "description": "Bereich fehlt (INSUFFICIENT_SCOPE), Recht fehlt (FORBIDDEN) oder Premium nötig (PREMIUM_REQUIRED)"
          },
          "404": {
            "description": "Nicht gefunden — auch für Organisationen, die der Schlüssel nicht sehen darf"
          },
          "429": {
            "description": "Zu viele Anfragen (RATE_LIMITED); Retry-After beachten"
          }
        },
        "x-codeSamples": [
          {
            "lang": "Shell",
            "label": "curl",
            "source": "curl -H \"Authorization: Bearer clup_k_…\" \"https://api.clup.life/api/v1/ext/exports/events.csv?from=2026-11-01T00:00:00Z&to=2026-12-01T00:00:00Z\""
          }
        ]
      }
    },
    "/ext/exports/organizations/{org}/members.csv": {
      "get": {
        "summary": "Mitgliederliste als CSV (nur Leitung, protokolliert)",
        "description": "Benötigte Bereiche: exports:read, members:read. Die Rechte der Person hinter dem Schlüssel gelten unverändert; fremde oder nicht sichtbare Organisationen antworten 404.",
        "security": [
          {
            "apiKey": [
              "exports:read",
              "members:read"
            ]
          }
        ],
        "parameters": [
          {
            "name": "org",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Kennung (slug) der Organisation"
          }
        ],
        "responses": {
          "200": {
            "description": "Erfolg",
            "content": {
              "text/csv": {
                "schema": {
                  "type": "string"
                }
              }
            }
          },
          "401": {
            "description": "Schlüssel ungültig, abgelaufen oder widerrufen (INVALID_API_KEY)"
          },
          "403": {
            "description": "Bereich fehlt (INSUFFICIENT_SCOPE), Recht fehlt (FORBIDDEN) oder Premium nötig (PREMIUM_REQUIRED)"
          },
          "404": {
            "description": "Nicht gefunden — auch für Organisationen, die der Schlüssel nicht sehen darf"
          },
          "429": {
            "description": "Zu viele Anfragen (RATE_LIMITED); Retry-After beachten"
          }
        },
        "x-codeSamples": [
          {
            "lang": "Shell",
            "label": "curl",
            "source": "curl -H \"Authorization: Bearer clup_k_…\" \"https://api.clup.life/api/v1/ext/exports/organizations/mein-verein/members.csv\""
          }
        ]
      }
    }
  },
  "components": {
    "securitySchemes": {
      "apiKey": {
        "type": "http",
        "scheme": "bearer",
        "bearerFormat": "clup_k_…",
        "description": "API-Schlüssel aus Einstellungen → Schnittstellen. Wird nur einmal angezeigt."
      }
    },
    "x-scopes": {
      "profile:read": {
        "writes": false
      },
      "directory:read": {
        "writes": false
      },
      "events:read": {
        "writes": false
      },
      "events:write": {
        "writes": true
      },
      "members:read": {
        "writes": false
      },
      "posts:read": {
        "writes": false
      },
      "announcements:read": {
        "writes": false
      },
      "announcements:write": {
        "writes": true
      },
      "tasks:read": {
        "writes": false
      },
      "tasks:write": {
        "writes": true
      },
      "presse:read": {
        "writes": false
      },
      "presse:write": {
        "writes": true
      },
      "exports:read": {
        "writes": false
      }
    }
  }
}
