Mit der öffentlichen API holst du die Anlässe deines Vereins in deine eigene Website und nimmst Mitgliedsanträge aus einem eigenen Formular entgegen, zum Beispiel in einem WordPress-Theme, einer Webflow-Seite oder einer App.
Für die meisten Vereine reicht das Einbetten: Formular einbetten und Veranstaltungen einbetten brauchen keine Programmierung. Die API ist für Entwicklerinnen und Entwickler, die alles selbst gestalten wollen.
Überblick
| Basis-URL | https://www.membear.ch/api/v1 |
| Format | JSON (UTF-8), Kalender als iCalendar (ICS) |
| Anmeldung | keine: die API liefert nur, was der Verein ohnehin veröffentlicht |
| CORS | offen für alle Websites (Access-Control-Allow-Origin: *) |
| Beträge | ganze Zahlen in Rappen (12000 = CHF 120.00) |
| Zeiten | ISO 8601 in UTC, z. B. 2026-11-14T18:30:00.000Z (Vereine sind in der Zeitzone Europe/Zurich) |
| OpenAPI | /api/v1/openapi.json, importierbar in Postman, Insomnia, Swagger UI oder Code-Generatoren |
{account} ist das Kürzel deines Vereins, wie im Link zum Anmeldeformular: bei https://www.membear.ch/fc-musterhausen ist es fc-musterhausen.
Endpunkte
| Methode | Pfad | Inhalt |
|---|---|---|
| GET | /{account}/events | öffentliche Anlässe, seitenweise |
| GET | /{account}/events/{eventId} | ein Anlass |
| GET | /{account}/events/calendar | Kalender-Feed (ICS) zum Abonnieren |
| GET | /{account}/signup-form | Mitgliedschaften, Felder und Zahlungsarten des Anmeldeformulars |
| POST | /{account}/signups | Mitgliedsantrag einreichen |
Veranstaltungen abrufen
curl "https://www.membear.ch/api/v1/fc-musterhausen/events?limit=3"
Ohne Parameter kommen die Anlässe, die noch nicht vorbei sind, der nächste zuerst. Nur veröffentlichte Anlässe mit Sichtbarkeit Öffentlich, Anlässe nur für Mitglieder nie.
| Parameter | Bedeutung | Standard |
|---|---|---|
from, to | Beginn ab / bis, inklusive. Ein Datum (2026-11-30) gilt als ganzer Tag in Schweizer Zeit; Datum mit Zeit ohne Zeitzone (2026-11-30T18:00) ebenfalls als Schweizer Zeit | ab jetzt |
include_past | true: auch vergangene Anlässe (wenn from fehlt) | false |
search | Text in Name oder Beschreibung | |
location | Text im Ort | |
registration_required | true / false | |
sort | date_asc oder date_desc | date_asc |
limit | 1 bis 100 pro Seite | 20 |
page | Seite, ab 1 | 1 |
Unbekannte Parameter (z. B. ein Cache-Buster _=…) werden ignoriert.
Antwort:
{
"data": [
{
"id": "6c1f7c2e-8a1b-4f43-9a7e-2b8d9f0e1a23",
"name": "Herbstwanderung",
"description": "Gemütliche Wanderung mit Grillplausch.",
"starts_at": "2026-11-14T08:00:00.000Z",
"ends_at": "2026-11-14T15:00:00.000Z",
"location": "Treffpunkt Bahnhof",
"price_rappen": 2500,
"currency": "CHF",
"registration": {
"required": true,
"deadline": "2026-11-10T22:59:00.000Z",
"open": true,
"max_participants": 30,
"spots_left": 12,
"waitlist": false,
"min_age": null,
"max_age": null,
"url": "https://www.membear.ch/members/login/fc-musterhausen"
},
"updated_at": "2026-10-20T09:12:44.000Z"
}
],
"pagination": { "page": 1, "limit": 3, "total": 7, "total_pages": 3 }
}
registration.open: Anmeldung ist nötig und noch möglich (vor der Frist bzw. vor Beginn).registration.spots_left: freie Plätze,nullohne Teilnehmerlimit.registration.url: Mitglieder melden sich im Mitgliederportal an; das ist dessen Login-Seite. Verlinke sie als Button «Anmelden».
Beispiel: nächste Anlässe in einer Website anzeigen
<ul id="anlaesse"></ul>
<script>
fetch('https://www.membear.ch/api/v1/fc-musterhausen/events?limit=5')
.then((response) => response.json())
.then(({ data }) => {
const list = document.getElementById('anlaesse');
const date = new Intl.DateTimeFormat('de-CH', {
dateStyle: 'medium',
timeStyle: 'short',
timeZone: 'Europe/Zurich',
});
for (const event of data) {
const item = document.createElement('li');
item.textContent = `${date.format(new Date(event.starts_at))} – ${event.name}`;
list.append(item);
}
});
</script>
Kalender-Feed
https://www.membear.ch/api/v1/fc-musterhausen/events/calendar?lang=de liefert alle öffentlichen Anlässe als iCalendar. Mit webcal:// statt https:// abonnieren Apple Kalender, Google Kalender und Outlook den Feed und bleiben automatisch aktuell. lang: de, en, fr oder it.
Mitgliedsanträge senden
Ein Antrag über die API durchläuft dieselben Regeln wie das eingebettete Formular: Pflichtfelder und Zusatzfelder deines Formulars, erlaubte Länder, Duplikatprüfung, Rechnung, Bestätigungs-E-Mail und Benachrichtigung an den Verein. Das Mitglied hat danach den Status Ausstehend, bis der Verein den Antrag annimmt.
1. Formular abfragen
curl "https://www.membear.ch/api/v1/fc-musterhausen/signup-form"
{
"data": {
"enabled": true,
"unavailable_reason": null,
"association": { "name": "FC Musterhausen", "slug": "fc-musterhausen" },
"membership_types": [
{
"id": "0b6f8c1e-3c2a-4d7e-9a51-2f3e4d5c6b7a",
"name": "Aktivmitglied",
"description": null,
"price_rappen": 12000,
"currency": "CHF"
}
],
"fields": [
{ "key": "phone", "required": false, "membership_type_ids": [] },
{ "key": "address", "required": true, "membership_type_ids": [], "allowed_countries": ["CH", "LI"] }
],
"custom_fields": [
{
"key": "tshirt_groesse",
"name": "T-Shirt-Grösse",
"description": null,
"type": "select",
"required": true,
"options": ["S", "M", "L", "XL"],
"membership_type_ids": []
}
],
"payment_methods": ["bank_transfer", "zahls"]
}
}
- Vorname, Nachname und E-Mail sind immer Pflicht.
fieldsnennt die zusätzlichen Standardfelder.addresssteht fürstreet,street_number,postal_code,cityundcountry.membership_type_idsleer heisst: gilt für alle Mitgliedschaften, sonst nur für die genannten.enabled: falsemitunavailable_reason:setup_incomplete(Zahlungen nicht eingerichtet),disabled(Online-Anmeldung ausgeschaltet) oderno_membership_types.
2. Antrag senden
curl -X POST "https://www.membear.ch/api/v1/fc-musterhausen/signups" \
-H "Content-Type: application/json" \
-d '{
"first_name": "Anna",
"last_name": "Muster",
"email": "anna.muster@example.ch",
"street": "Bahnhofstrasse",
"street_number": "1",
"postal_code": "8001",
"city": "Zürich",
"country": "CH",
"membership_type_id": "0b6f8c1e-3c2a-4d7e-9a51-2f3e4d5c6b7a",
"custom_fields": { "tshirt_groesse": "M" },
"payment_method": "zahls"
}'
| Feld | Pflicht | Hinweis |
|---|---|---|
first_name, last_name | ja | max. 100 Zeichen |
email | ja | |
membership_type_id | ja | aus membership_types |
payment_method | ja | zahls (TWINT, Karte) oder bank_transfer (QR-Rechnung), siehe payment_methods |
phone, street, street_number, postal_code, city, state, notes | je nach Formular | |
country | je nach Formular | ISO-Code mit zwei Buchstaben, z. B. CH |
date_of_birth | je nach Formular | JJJJ-MM-TT |
custom_fields | je nach Formular | Werte nach key; unbekannte oder ausgeblendete Felder werden ignoriert |
Unbekannte Felder im JSON lehnt die API mit 400 ab, damit Tippfehler auffallen.
3. Antwort auswerten
201 – Antrag eingegangen:
{
"data": {
"status": "received",
"member_status": "pending",
"payment": {
"method": "zahls",
"amount_rappen": 12000,
"currency": "CHF",
"checkout_url": "https://…",
"bank_transfer": null
}
}
}
zahls: leite die Person zucheckout_urlweiter, dort bezahlt sie mit TWINT oder Karte.bank_transfer: zeige die Angaben ausbank_transfer(IBAN, Referenz). Die QR-Rechnung kommt zusätzlich per E-Mail.
200 – schon Mitglied: Gibt es bereits ein Mitglied mit dieser E-Mail und Mitgliedschaft, wird nichts angelegt. Die Person erhält per E-Mail einen Link zum Mitgliederportal, die Antwort ist { "data": { "status": "existing_member", … } }.
Fehler
Alle Fehler haben dieselbe Form:
{
"error": {
"code": "invalid_request",
"message": "The request is invalid.",
"details": [{ "field": "email", "message": "Invalid email" }]
}
}
| Status | code | Bedeutung |
|---|---|---|
| 400 | invalid_request | Parameter oder JSON ungültig; details nennt die Felder |
| 403 | signup_unavailable | Verein nimmt gerade keine Online-Anmeldungen an |
| 404 | not_found | Verein oder Anlass unbekannt, oder Anlass nicht öffentlich |
| 422 | validation_failed | Regel des Formulars verletzt, z. B. Pflichtfeld fehlt |
| 429 | rate_limited | zu viele Anfragen, Header Retry-After nennt die Sekunden |
| 500 | internal_error | Fehler bei uns; später erneut versuchen |
Limits und Schutz vor Spam
| Was | Limit |
|---|---|
| Lesen (alle GET), pro IP-Adresse | 300 Anfragen in 5 Minuten |
| Anträge, pro IP-Adresse | 10 pro Stunde |
| Anträge, pro Verein (API und Formular zusammen) | 30 pro Stunde |
| Anträge, pro E-Mail-Adresse und Verein | 3 pro Tag |
Antworten der GET-Endpunkte werden bis zu einer Minute zwischengespeichert. Schickst du alle Anträge von deinem eigenen Server, teilen sie sich das Limit pro IP-Adresse; sende sie deshalb wenn möglich direkt aus dem Browser deiner Besucherinnen und Besucher (CORS ist offen).
Versionen
Die API ist versioniert (/api/v1). Innerhalb von v1 kommen höchstens neue Felder und Endpunkte dazu; dein Code sollte unbekannte Felder ignorieren. Änderungen, die bestehende Integrationen brechen, gibt es nur mit einer neuen Version.