API-Dokumentation
Die botcmap.de API ermöglicht es, Events programmatisch anzulegen, zu verwalten und Events in der Nähe abzufragen – z.B. über Discord-Bots oder eigene Skripte.
API-Keys können unter Konto → API-Keys generiert werden.
Maschinenlesbare Spezifikation: /api/v1/openapi.json (OpenAPI 3.1)
Authentifizierung
Alle Endpoints erfordern einen API-Key im Authorization-Header:
Authorization: Bearer botcmap_sk_<dein-key>
Schreibende Endpoints (POST, PATCH) erfordern außerdem:
Content-Type: application/json
Scopes
Jeder Key hat einen oder mehrere Scopes. Beim Generieren wählbar:
| Scope | Endpoints |
|---|---|
read | Alle GET-Endpoints |
write | Events anlegen, bearbeiten, veröffentlichen, stornieren, Serien anlegen |
participants | Teilnehmer hinzufügen, Status ändern |
community | Community Events einreichen |
Rate-Limit
Max. 50 Events pro Key pro Tag. Jede schreibende Antwort enthält:
X-RateLimit-Limit: 50
X-RateLimit-Remaining: 47
X-RateLimit-Reset: 1746057600
Bei Überschreitung: 429 Too Many Requests.
Abgelaufene Keys
Keys mit gesetztem Ablaufdatum liefern nach dem Ablauf 401 Unauthorized: API key has expired.
Sandbox-Key
Ein schreibgeschützter Test-Key (nur read-Scope) kann über den Button „Sandbox-Key generieren“ erstellt werden – kein Event anlegen möglich, perfekt zum Ausprobieren.
Übersicht aller Endpoints
| Methode | Pfad | Scope | Beschreibung |
|---|---|---|---|
GET | /api/v1/map/feed | read | Plattformweiter Karten-Feed (Runden + Community-Events) für Partner-Importe |
GET | /api/v1/events/nearby | read | Events in der Nähe (PLZ / Stadt / lat+lng) |
GET | /api/v1/events/mine | read | Alle eigenen Events (inkl. Entwürfe) |
GET | /api/v1/events/{id} | read | Event-Details |
POST | /api/v1/events | write | Event anlegen |
PATCH | /api/v1/events/{id} | write | Event bearbeiten (Partial Update) |
POST | /api/v1/events/{id}/publish | write | Entwurf veröffentlichen |
POST | /api/v1/events/{id}/cancel | write | Event stornieren |
GET | /api/v1/events/{id}/participants | read | Teilnehmerliste (nur eigene Events) |
POST | /api/v1/events/{id}/participants | participants | Gast-Teilnehmer hinzufügen |
PATCH | /api/v1/events/{id}/participants/{userId} | participants | Teilnehmerstatus ändern |
GET | /api/v1/events/{id}/ratings | read | Bewertungen eines Events (anonymisiert) |
POST | /api/v1/series | write | Serienevent anlegen |
GET | /api/v1/scripts | read | Alle bekannten Scripte |
GET | /api/v1/storytellers/{id} | read | Öffentliches Storyteller-Profil |
POST | /api/v1/community-events | community | Community Event einreichen |
GET | /api/v1/openapi.json | read | OpenAPI 3.1 Spezifikation |
GET /api/v1/events/nearby
Öffentliche Events in einem Radius. DSGVO: keine exakten Adressen oder GPS-Koordinaten in der Antwort.
| Parameter | Typ | Pflicht | Default | Beschreibung |
|---|---|---|---|---|
postal_code | string | Ja* | – | PLZ des Suchzentrums |
city | string | Ja* | – | Stadtname als Alternative zur PLZ |
lat | float | Ja* | – | Breitengrad (zusammen mit lng) |
lng | float | Ja* | – | Längengrad (zusammen mit lat) |
radius_km | int | Nein | 50 | Suchradius in km, max. 200 |
from | date | Nein | heute | Startdatum YYYY-MM-DD |
to | date | Nein | – | Enddatum YYYY-MM-DD |
difficulty_min | int | Nein | – | Min. Schwierigkeit (1–10) |
difficulty_max | int | Nein | – | Max. Schwierigkeit (1–10) |
beginner_only | bool | Nein | false | Nur Einsteiger-Events (1 oder true) |
page | int | Nein | 1 | Seitennummer |
per_page | int | Nein | 50 | Ergebnisse pro Seite (max. 100) |
fields | string | Nein | – | Kommaliste gewünschter Felder, z.B. id,title,free_slots |
GET /api/v1/events/nearby?city=Berlin&radius_km=30&page=1&per_page=10
Authorization: Bearer botcmap_sk_...
{
"data": [{
"id": "a1b2c3d4",
"url": "https://botcmap.de/event/a1b2c3d4",
"title": "Trouble Night",
"date": "2026-05-10",
"start_time": "18:00",
"city": "Berlin",
"postal_code": "10115",
"difficulty_min": 3,
"difficulty_max": 7,
"is_beginner_friendly": false,
"free_slots": 2,
"max_players": 12,
"scripts": [{ "name": "Trouble Brewing", "type": "official" }]
}],
"meta": { "total": 23, "page": 1, "per_page": 10, "pages": 3, "radius_km": 30, "from": "2026-04-17" }
}
GET /api/v1/map/feed
Plattformweiter Karten-Feed für Partner-Importe (z.B. brettspielabende.de): alle öffentlich sichtbaren Runden (published, nicht privat/abgesagt/versteckt) und alle freigegebenen Community-Events – jeweils mit anonymisierter Koordinate, Datum und Link. Standardmäßig nur kommende Events. Scope: read.
| Parameter | Typ | Pflicht | Default | Beschreibung |
|---|---|---|---|---|
from | date | Nein | heute | Nur Events ab diesem Datum YYYY-MM-DD |
to | date | Nein | – | Nur Events bis zu diesem Datum |
country | string | Nein | – | Auf ein Land filtern: de, at oder ch |
beginner_only | bool | Nein | false | Nur Einsteiger-Events |
page | int | Nein | 1 | Seitennummer |
per_page | int | Nein | 200 | Ergebnisse pro Seite (max. 500) |
GET /api/v1/map/feed?country=de&per_page=200
Authorization: Bearer botcmap_sk_...
{
"data": [
{
"type": "round",
"id": "a1b2c3d4",
"url": "https://botcmap.de/event/a1b2c3d4",
"title": "Trouble Night",
"date": "2026-05-10",
"start_time": "18:00",
"city": "Berlin",
"postal_code": "10115",
"region": "Berlin",
"country": "de",
"lat": 52.51,
"lng": 13.38,
"is_beginner_friendly": false
},
{
"type": "community",
"id": "bounty-hunter-12e8",
"url": "https://botcmap.de/community-event/bounty-hunter-12e8",
"title": "Bounty Hunter Night",
"date": "2026-05-12",
"start_time": "19:00",
"city": "Hamburg",
"postal_code": "20095",
"region": null,
"country": "de",
"lat": 53.55,
"lng": 9.99,
"is_beginner_friendly": true
}
],
"meta": { "total": 42, "page": 1, "per_page": 200, "pages": 1, "from": "2026-04-17" }
}
type unterscheidet "round" (normale Runde) von "community" (Community-Event). Die Koordinaten (lat/lng) sind anonymisiert – gleiche Genauigkeit wie die öffentliche Karte.
GET /api/v1/events/mine
Alle eigenen Events – inkl. Entwürfe, abgesagte und abgeschlossene. Scope: read.
GET /api/v1/events/mine
Authorization: Bearer botcmap_sk_...
{
"data": [{
"id": "a1b2c3d4",
"url": "https://botcmap.de/event/a1b2c3d4",
"title": "Trouble Night",
"date": "2026-05-10",
"start_time": "18:00",
"city": "Berlin",
"postal_code": "10115",
"lat": 52.51,
"lng": 13.38,
"status": "published",
"max_players": 12,
"confirmed": 8,
"requested": 2,
"free_slots": 4
}],
"meta": { "total": 5 }
}
lat/lng sind anonymisierte Koordinaten (gleiche Genauigkeit wie die öffentliche Karte) – ideal für eigene Karten-Ansichten. Können null sein, falls keine Koordinaten hinterlegt sind.
GET /api/v1/events/{id}
Vollständige Event-Details. Eigene Entwurfs-Events sind auch lesbar. Scope: read.
GET /api/v1/events/a1b2c3d4
Authorization: Bearer botcmap_sk_...
{
"id": "a1b2c3d4",
"url": "https://botcmap.de/event/a1b2c3d4",
"title": "Trouble Night",
"description": "Eine entspannte Runde für alle.",
"date": "2026-05-10",
"start_time": "18:00",
"duration_hours": 4,
"city": "Berlin",
"postal_code": "10115",
"country": "Deutschland",
"status": "published",
"max_players": 12,
"min_players": 5,
"confirmed_slots": 8,
"requested_slots": 2,
"waitlist_slots": 1,
"free_slots": 4,
"difficulty_min": 3,
"difficulty_max": 7,
"is_beginner_friendly": false,
"confirmation_mode": "manual",
"scripts": [{ "name": "Trouble Brewing", "type": "official" }],
"storyteller": "Max"
}
POST /api/v1/events — Event anlegen
Legt ein neues Event an. Erfordert freigeschalteten Storyteller-Account. Scope: write.
| Feld | Typ | Pflicht | Beschreibung |
|---|---|---|---|
title | string | ✓ | Titel des Events |
event_date | string | ✓ | Datum YYYY-MM-DD |
start_time | string | ✓ | Uhrzeit HH:MM |
address | string | ✓ | Vollständige Adresse inkl. Hausnr. (wird verschlüsselt) |
postal_code | string | ✓ | Postleitzahl |
city | string | ✓ | Ort |
max_players | int | ✓ | Max. Spieleranzahl (min. 5) |
publish | bool | – | true → sofort veröffentlicht; absent/false → Entwurf |
description | string | – | Beschreibung |
duration_hours | float | – | Dauer in Stunden (default: 4) |
min_players | int | – | Min. Spieleranzahl (default: 5) |
difficulty_min | int | – | Min. Schwierigkeit 1–10 |
difficulty_max | int | – | Max. Schwierigkeit 1–10 |
is_beginner_friendly | bool | – | Einsteiger-freundlich |
confirmation_mode | string | – | "manual" (default) oder "auto" |
country | string | – | Land (default: "Deutschland") |
POST /api/v1/events
Authorization: Bearer botcmap_sk_...
Content-Type: application/json
{
"title": "Trouble Night",
"event_date": "2026-06-15",
"start_time": "19:00",
"address": "Musterstr. 1, 10115 Berlin",
"postal_code": "10115",
"city": "Berlin",
"max_players": 12,
"difficulty_min": 3,
"difficulty_max": 7,
"publish": false
}
→ 201 Created
{ "id": "a1b2c3d4", "url": "https://botcmap.de/event/a1b2c3d4", "status": "draft" }
PATCH /api/v1/events/{id} — Event bearbeiten
Partial Update: nur gesendete Felder werden geändert. Adresse wird nur neu geocodiert wenn address gesendet wird. Scope: write.
| Feld | Typ | Beschreibung |
|---|---|---|
title | string | Neuer Titel |
event_date | string | Neues Datum YYYY-MM-DD |
start_time | string | Neue Uhrzeit HH:MM |
address | string | Neue Adresse (mit postal_code + city angeben) |
description | string | Neue Beschreibung |
max_players | int | Neue max. Spielerzahl |
min_players | int | Neue min. Spielerzahl |
difficulty_min | int | Min. Schwierigkeit 1–10 |
difficulty_max | int | Max. Schwierigkeit 1–10 |
is_beginner_friendly | bool | Einsteiger-freundlich |
duration_hours | float | Dauer in Stunden |
Antwort 200 OK: {"id": "...", "url": "...", "status": "published"}
POST /api/v1/events/{id}/publish — Entwurf veröffentlichen
Veröffentlicht ein eigenes Entwurfs-Event. Kein Body nötig. Scope: write.
POST /api/v1/events/a1b2c3d4/publish
Authorization: Bearer botcmap_sk_...
→ 200 OK
{ "id": "a1b2c3d4", "url": "https://botcmap.de/event/a1b2c3d4", "status": "published" }
POST /api/v1/events/{id}/cancel — Event stornieren
Setzt ein eigenes Event auf cancelled. Kein Body nötig. Nicht rückgängig machbar via API. Scope: write.
POST /api/v1/events/a1b2c3d4/cancel
Authorization: Bearer botcmap_sk_...
→ 200 OK
{ "id": "a1b2c3d4", "status": "cancelled" }
GET /api/v1/events/{id}/participants — Teilnehmerliste
Teilnehmerliste eines eigenen Events. Nur der Storyteller-Owner hat Zugriff. Scope: read.
GET /api/v1/events/a1b2c3d4/participants
Authorization: Bearer botcmap_sk_...
{
"data": [
{
"user_id": 42,
"name": "Anna",
"status": "confirmed",
"plus_one": false,
"join_message": "Freue mich!",
"requested_at": "2026-04-10"
},
{
"user_id": null,
"name": "Max (Gast)",
"status": "confirmed",
"plus_one": false,
"join_message": null,
"requested_at": null
}
],
"meta": { "total": 2 }
}
Gäste (ohne Account) haben user_id: null. Status-Werte: confirmed, requested, waitlist, cancelled, attended, no_show.
POST /api/v1/events/{id}/participants — Teilnehmer hinzufügen
Fügt einen Gast-Teilnehmer (ohne Account) zu einem eigenen Event hinzu. Scope: participants.
| Feld | Typ | Pflicht | Beschreibung |
|---|---|---|---|
name | string | ✓ | Name des Gastes |
plus_one | bool | – | Kommt mit einer Begleitperson (default: false) |
POST /api/v1/events/a1b2c3d4/participants
Authorization: Bearer botcmap_sk_...
Content-Type: application/json
{ "name": "Max Mustermann", "plus_one": false }
→ 201 Created
{ "participant_id": 99, "name": "Max Mustermann", "status": "confirmed", "plus_one": false }
PATCH /api/v1/events/{id}/participants/{userId} — Teilnehmerstatus ändern
Ändert den Status eines Teilnehmers (mit Account) auf einem eigenen Event. userId aus der Teilnehmerliste. Scope: participants.
| Feld | Typ | Pflicht | Beschreibung |
|---|---|---|---|
status | string | ✓ | confirmed, waitlist, cancelled, attended, no_show |
PATCH /api/v1/events/a1b2c3d4/participants/42
Authorization: Bearer botcmap_sk_...
Content-Type: application/json
{ "status": "confirmed" }
→ 200 OK
{ "user_id": 42, "status": "confirmed" }
GET /api/v1/events/{id}/ratings — Bewertungen
Storyteller-Bewertungen eines vergangenen Events (anonymisiert – keine Nutzernamen). Nur für veröffentlichte oder abgeschlossene Events. Scope: read.
GET /api/v1/events/a1b2c3d4/ratings
Authorization: Bearer botcmap_sk_...
{
"event_id": "a1b2c3d4",
"count": 5,
"avg_orga": 4.2,
"avg_rules_confidence": 4.5,
"avg_atmosphere": 4.3,
"avg_location": 4.0,
"avg_overall": 4.25,
"ratings": [
{ "orga": 5, "rules_confidence": 5, "atmosphere": 4, "location": 4, "date": "2026-04-01" }
]
}
POST /api/v1/series — Serienevent anlegen
Legt ein Serienevent mit mehreren Terminen an. Scope: write.
| Feld | Typ | Pflicht | Beschreibung |
|---|---|---|---|
title | string | ✓ | Serientitel |
occurrences | array | ✓ | Liste von {"event_date": "YYYY-MM-DD", "start_time": "HH:MM"} |
address | string | ✓ | Adresse (gilt für alle Termine) |
postal_code | string | ✓ | Postleitzahl |
city | string | ✓ | Ort |
max_players | int | ✓ | Max. Spieleranzahl |
publish | bool | – | true → sofort veröffentlicht |
description | string | – | Beschreibung |
difficulty_min | int | – | Min. Schwierigkeit |
difficulty_max | int | – | Max. Schwierigkeit |
is_beginner_friendly | bool | – | Einsteiger-freundlich |
POST /api/v1/series
Authorization: Bearer botcmap_sk_...
Content-Type: application/json
{
"title": "Montags-Runde",
"address": "Musterstr. 1",
"postal_code": "10115",
"city": "Berlin",
"max_players": 12,
"publish": true,
"occurrences": [
{ "event_date": "2026-05-05", "start_time": "19:00" },
{ "event_date": "2026-05-12", "start_time": "19:00" },
{ "event_date": "2026-05-19", "start_time": "19:00" }
]
}
→ 201 Created
{
"series_id": 7,
"occurrences": 3,
"status": "published",
"first_event": { "id": "a1b2c3d4", "url": "https://botcmap.de/event/a1b2c3d4" }
}
GET /api/v1/scripts — Scriptliste
Alle bekannten Scripte (nur aktive). Scope: read.
GET /api/v1/scripts
Authorization: Bearer botcmap_sk_...
{
"data": [
{
"id": 1,
"name": "Trouble Brewing",
"type": "official",
"difficulty": 2,
"color": "green",
"is_beginner_friendly": true,
"recommended_min_players": 5,
"recommended_max_players": 15,
"url": "https://botcscripts.com/script/trouble_brewing"
}
],
"meta": { "total": 12 }
}
GET /api/v1/storytellers/{id} — Storyteller-Profil
Öffentliche Storyteller-Daten. id = User-ID. Scope: read.
GET /api/v1/storytellers/42
Authorization: Bearer botcmap_sk_...
{
"id": 42,
"name": "Max",
"city": "Berlin",
"bio": "Spiele seit 2022...",
"follower_count": 18,
"event_count": 34,
"avg_rating": 4.7,
"rating_count": 28,
"url": "https://botcmap.de/storyteller/42"
}
POST /api/v1/community-events — Community Event einreichen
Wie das Web-Formular, aber per API. Geht durch Admin-Freigabe. Scope: community.
| Feld | Typ | Pflicht | Beschreibung |
|---|---|---|---|
title | string | ✓ | Titel |
event_date | string | ✓ | Datum YYYY-MM-DD |
start_time | string | ✓ | Uhrzeit HH:MM |
address | string | ✓ | Adresse |
postal_code | string | ✓ | Postleitzahl |
city | string | ✓ | Ort |
submitter_email | string | ✓ | Kontakt-E-Mail (nicht öffentlich) |
submitter_name | string | – | Name der einreichenden Person |
description | string | – | Beschreibung |
location_name | string | – | Name des Veranstaltungsorts |
contact_discord | string | – | Discord-Handle |
website_url | string | – | URL zur Anmeldung/Info |
script_info | string | – | Script-Info (Freitext) |
is_beginner_friendly | bool | – | Einsteiger-freundlich |
Antwort 201 Created: {"id": "...", "status": "pending", "message": "..."}
HTTP-Statuscodes
| Code | Bedeutung |
|---|---|
200 | Erfolg |
201 | Erstellt |
401 | Kein, ungültiger oder abgelaufener API-Key |
403 | Key gültig, aber fehlender Scope oder kein freigeschalteter Storyteller |
404 | Event nicht gefunden oder gehört nicht zum API-Key-Inhaber |
415 | Falscher Content-Type (erwartet application/json) |
422 | Validierungsfehler – error-Feld enthält Details |
429 | Rate-Limit erreicht (max. 50 Events/Key/Tag) |
500 | Serverfehler |