Schnellstart
In vier Schritten vom Schlüssel zu einer funktionierenden Anbindung. Rechnen Sie mit zehn Minuten.
1. Einen Schlüssel erstellen
Ein Administrator des Vereins erstellt Schlüssel in Mitgliederbuch unter Einstellungen → API-Schlüssel → Neuer Schlüssel. Geben Sie dem Schlüssel einen Namen, an dem Sie später erkennen, wofür er ist, und wählen Sie die Rechte. Standardmäßig ist alles nur lesbar; für Schritt 4 brauchen Sie zusätzlich leden:schrijven.
Der Schlüssel wird einmal angezeigt. Legen Sie ihn in einer Umgebungsvariable ab und nicht im Code:
export LEDENBOEK_API_KEY="lb_test_..."In einem Beispielverein beginnt der Schlüssel mit lb_test_. Dort werden keine E-Mails und keine Zahlungsaufforderungen verschickt, Sie können also alles ausprobieren, ohne echte Mitglieder zu berühren.
2. Ihr erster Aufruf
GET /v2/organization funktioniert mit jedem Schlüssel und liefert den Verein, die aktivierten Module und die Rechte Ihres Schlüssels. Eine gute erste Prüfung, ob alles stimmt.
curl https://api.mitgliederbuch.de/v2/organization \
-H "Authorization: Bearer $LEDENBOEK_API_KEY"const response = await fetch("https://api.mitgliederbuch.de/v2/organization", {
headers: { Authorization: `Bearer ${process.env.LEDENBOEK_API_KEY}` },
});
const organization = await response.json();
console.log(organization.name, organization.api_key.scopes);<?php
$ch = curl_init("https://api.mitgliederbuch.de/v2/organization");
curl_setopt_array($ch, [
CURLOPT_HTTPHEADER => ["Authorization: Bearer " . getenv("LEDENBOEK_API_KEY")],
CURLOPT_RETURNTRANSFER => true,
]);
$organization = json_decode(curl_exec($ch), true);
echo $organization["name"];import os
import requests
response = requests.get(
"https://api.mitgliederbuch.de/v2/organization",
headers={"Authorization": f"Bearer {os.environ['LEDENBOEK_API_KEY']}"},
)
organization = response.json()
print(organization["name"], organization["api_key"]["scopes"])Die Antwort:
{
"object": "organization",
"id": 42,
"name": "SV Grün-Weiß",
"slug": "sv-gruen-weiss",
"country": "Deutschland",
"language": "de",
"website_url": "https://www.sv-gruen-weiss.de",
"modules": {
"groups": true,
"committees": true,
"participants": false,
"relationships": false,
"events": true,
"invoicing": true
},
"api_key": {
"name": "Anbindung der Website",
"prefix": "lb_test_8kQz",
"environment": "test",
"scopes": [
"leden:lezen",
"leden:schrijven"
]
}
}Ein 401 bedeutet meist, dass der Header nicht genau Authorization: Bearer lb_... lautet. Bei 402 hat der Verein kein gültiges Abonnement.
3. Durch Mitglieder blättern
Mit dem Recht leden:lezen rufen Sie Mitglieder mit GET /v2/members ab. Listen kommen in Seiten von höchstens 100 Datensätzen (standardmäßig 25). Solange has_more wahr ist, fragen Sie die nächste Seite ab, indem Sie next_cursor als starting_after mitgeben.
curl "https://api.mitgliederbuch.de/v2/members?limit=100" \
-H "Authorization: Bearer $LEDENBOEK_API_KEY"
# Next page: pass next_cursor from the previous response
curl "https://api.mitgliederbuch.de/v2/members?limit=100&starting_after=1234" \
-H "Authorization: Bearer $LEDENBOEK_API_KEY"const headers = { Authorization: `Bearer ${process.env.LEDENBOEK_API_KEY}` };
const members = [];
let cursor = null;
do {
const url = new URL("https://api.mitgliederbuch.de/v2/members");
url.searchParams.set("limit", "100");
if (cursor) url.searchParams.set("starting_after", cursor);
const page = await (await fetch(url, { headers })).json();
members.push(...page.data);
cursor = page.has_more ? page.next_cursor : null;
} while (cursor);<?php
$members = [];
$cursor = null;
do {
$query = http_build_query(array_filter(["limit" => 100, "starting_after" => $cursor]));
$ch = curl_init("https://api.mitgliederbuch.de/v2/members?" . $query);
curl_setopt_array($ch, [
CURLOPT_HTTPHEADER => ["Authorization: Bearer " . getenv("LEDENBOEK_API_KEY")],
CURLOPT_RETURNTRANSFER => true,
]);
$page = json_decode(curl_exec($ch), true);
$members = array_merge($members, $page["data"]);
$cursor = $page["has_more"] ? $page["next_cursor"] : null;
} while ($cursor !== null);import os
import requests
session = requests.Session()
session.headers["Authorization"] = f"Bearer {os.environ['LEDENBOEK_API_KEY']}"
members, cursor = [], None
while True:
params = {"limit": 100}
if cursor:
params["starting_after"] = cursor
page = session.get("https://api.mitgliederbuch.de/v2/members", params=params).json()
members.extend(page["data"])
if not page["has_more"]:
break
cursor = page["next_cursor"]Eine Seite sieht so aus (gekürzt; alle Felder stehen in der Referenz):
{
"object": "list",
"data": [
{
"object": "member",
"id": 1234,
"membership_number": "L042",
"first_name": "Anna",
"last_name": "Schmidt",
"email": "anna@example.com",
"status": "active",
"member_since": "2024-03-01",
"created_at": "2024-03-01T10:12:00+01:00",
"updated_at": "2026-10-02T08:30:00+02:00"
}
],
"has_more": true,
"next_cursor": "1234"
}4. Ein Mitglied anlegen
Mit leden:schrijven legen Sie mit POST /v2/members ein Mitglied an. Senden Sie einen Idempotency-Key mit: einen eindeutigen Wert pro neuem Mitglied, etwa eine UUID. Bricht die Verbindung ab und Sie senden dieselbe Anfrage mit demselben Schlüssel erneut, bekommen Sie die erste Antwort zurück und das Mitglied wird nicht doppelt angelegt.
curl https://api.mitgliederbuch.de/v2/members \
-X POST \
-H "Authorization: Bearer $LEDENBOEK_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: 6f1c2a3e-8d4b-4c1e-9a7f-2b5d0e9c4a11" \
-d '{"first_name": "Anna", "last_name": "de Vries", "email": "anna@example.com"}'// Store this key with your own record, so a retry sends the same one.
const idempotencyKey = crypto.randomUUID();
const response = await fetch("https://api.mitgliederbuch.de/v2/members", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.LEDENBOEK_API_KEY}`,
"Content-Type": "application/json",
"Idempotency-Key": idempotencyKey,
},
body: JSON.stringify({ first_name: "Anna", last_name: "de Vries", email: "anna@example.com" }),
});
const member = await response.json();<?php
// Store this key with your own record, so a retry sends the same one.
$idempotencyKey = bin2hex(random_bytes(16));
$ch = curl_init("https://api.mitgliederbuch.de/v2/members");
curl_setopt_array($ch, [
CURLOPT_POST => true,
CURLOPT_HTTPHEADER => [
"Authorization: Bearer " . getenv("LEDENBOEK_API_KEY"),
"Content-Type: application/json",
"Idempotency-Key: " . $idempotencyKey,
],
CURLOPT_POSTFIELDS => json_encode([
"first_name" => "Anna",
"last_name" => "de Vries",
"email" => "anna@example.com",
]),
CURLOPT_RETURNTRANSFER => true,
]);
$member = json_decode(curl_exec($ch), true);import os
import uuid
import requests
# Store this key with your own record, so a retry sends the same one.
idempotency_key = str(uuid.uuid4())
response = requests.post(
"https://api.mitgliederbuch.de/v2/members",
headers={
"Authorization": f"Bearer {os.environ['LEDENBOEK_API_KEY']}",
"Idempotency-Key": idempotency_key,
},
json={"first_name": "Anna", "last_name": "de Vries", "email": "anna@example.com"},
)
member = response.json()Ist ein Feld ungültig, bekommen Sie 422 mit einer Angabe pro Feld:
{
"type": "https://developers.mitgliederbuch.de/errors/validation_failed",
"title": "Daten ungültig",
"status": 422,
"detail": "Ein oder mehrere Felder sind nicht korrekt ausgefüllt; siehe errors.",
"instance": "/v2/members",
"errors": [
{
"field": "email",
"code": "invalid",
"message": "E-Mail ist ungültig"
}
]
}Weiter
- Authentifizierung: welche Rechte es gibt und was ein Testschlüssel anders macht.
- Konzepte: mit
updated_sincenur abholen, was sich geändert hat. - API-Referenz: alle Endpunkte. Mit der Spezifikation unter /openapi.json erzeugen Sie selbst einen Client in Ihrer Sprache, zum Beispiel mit OpenAPI Generator.