API-Integrationsleitfaden
Mit dieser Schnittstelle spielen Vereine Standorte und Einsätze direkt aus ihren eigenen Systemen ein. Jeder Zugang gehört genau zu einem Verein – die Vereinszuordnung kommt ausschliesslich aus dem Schlüssel.
1. Zugang erhalten
- Als Vereins-Admin anmelden und Verein → API öffnen.
- Einen benannten Zugangsschlüssel erstellen und sofort kopieren – er wird nur einmal angezeigt.
- Den Schlüssel im eigenen System sicher hinterlegen (nie im Browser-Code oder in öffentlichen Repositories).
Der Widerruf eines Schlüssels wirkt sofort. Schlüssel beginnen mit bm_live_; gespeichert wird nur ein Hash.
2. Authentifizierung
Jede Anfrage trägt den Schlüssel im Authorization-Header:
HTTP-Header
Authorization: Bearer bm_live_DEIN_SCHLUESSELBasis-URL: https://deine-app.lovable.app · CORS ist für externe Web-Anwendungen offen.
3. Endpunkte
Import: POST https://deine-app.lovable.app/api/public/v1/import
Referenz: GET https://deine-app.lovable.app/api/public/v1/reference
Der Referenz-Endpunkt liefert die erlaubten Werte und den Massnahmenkatalog des eigenen Vereins inklusive der IDs, die in measures[].measure_id verwendet werden.
Referenz abrufen
GET /api/public/v1/reference
Authorization: Bearer bm_live_DEIN_SCHLUESSEL
HTTP 200
{
"ok": true,
"reference": {
"site_types": ["magerwiese", "feuchtgebiet", "..."],
"poi_kinds": ["obstbaum", "trockenmauer", "nisthilfe", "steinhaufen", "sandlinse", "totholzhaufen", "feuchtbiotop", "asthaufen", "sonstiges"],
"poi_conditions": ["gut", "pflegebeduerftig", "beschaedigt", "unbekannt"],
"date_precisions": ["exact", "month", "year"],
"evidence_sources": ["protocol", "measurement", "photo", "estimate", "memory"],
"measure_statuses": ["planned", "done", "not_done"],
"taxonomic_groups": ["flora", "insects", "birds", "amphibians_reptiles", "mammals", "other"],
"modules": { "events": true, "pois": true, "observations": true },
"measures": [
{ "id": "UUID", "category": "Flaechenpflege", "name": "Mähen", "default_unit": "m²" }
]
}
}4. Unterstützte Felder
Standorte (sites)
| Feld | Typ | Beschreibung |
|---|---|---|
external_id | Text (Pflicht) | Eindeutige ID im eigenen System; erneutes Senden aktualisiert den Standort |
name | Text (Pflicht) | Name des Standorts |
site_type | Auswahl | magerwiese, feuchtgebiet, ruderalflaeche, hecke_gehoelz, obstgarten, gewaesser, waldrand, sonstiges |
description | Text | Beschreibung |
area_sqm | Ganzzahl | Fläche in m² |
latitude / longitude | Zahl | WGS84-Koordinaten (Schweiz) |
landowner_partner | Text | Grundeigentümer oder Partner |
focus_species | Liste von Texten | Fokusarten |
is_sensitive | Ja/Nein | Sensible Fläche (Koordinaten werden geschützt dargestellt) |
active | Ja/Nein | Aktiver Standort |
Naturwerte (pois)
| Feld | Typ | Beschreibung |
|---|---|---|
external_id | Text (Pflicht) | Eindeutige ID im eigenen System; erneutes Senden aktualisiert den Naturwert |
site_external_id | Text | Standort, zu dem der Naturwert gehört |
name | Text (Pflicht) | Bezeichnung, z.B. «Nisthilfe Nr. 14» |
kind | Auswahl | obstbaum, trockenmauer, nisthilfe, steinhaufen, sandlinse, totholzhaufen, feuchtbiotop, asthaufen, sonstiges |
detail | Text | Sorte, Zielart oder ähnliche Angabe |
year_created | Ganzzahl | Pflanz- oder Erstellungsjahr |
latitude / longitude | Zahl | WGS84-Koordinaten |
condition | Auswahl | gut, pflegebeduerftig, beschaedigt, unbekannt |
notes | Text | Notizen |
is_active | Ja/Nein | Noch vorhanden |
Einsätze (events)
| Feld | Typ | Beschreibung |
|---|---|---|
external_id | Text (Pflicht) | Eindeutige ID im eigenen System |
site_external_id | Text | Verweis auf den Standort; weglassen für Einsätze ohne festen Standort |
title | Text (Pflicht) | Titel des Einsatzes |
event_date | Datum (Pflicht) | Format JJJJ-MM-TT |
date_precision | Auswahl | exact, month oder year |
participants_count | Ganzzahl | Anzahl Teilnehmende |
duration_hours | Zahl | Dauer in Stunden |
volunteer_hours | Zahl | Personenstunden; wird aus Teilnehmende × Dauer berechnet, falls nicht geliefert |
evidence_source | Auswahl | protocol, measurement, photo, estimate, memory |
external_url | Text | Link zum Einsatz auf der eigenen Vereins-Website |
is_external_managed | Ja/Nein | Einsatz wird im eigenen System gepflegt |
notes | Text | Notizen |
measures | Liste | Bis zu 50 Massnahmen (siehe unten) |
observations | Liste | Bis zu 50 Artbeobachtungen (siehe unten) |
Massnahmen (measures)
| Feld | Typ | Beschreibung |
|---|---|---|
measure_id | UUID (Pflicht) | ID aus dem Referenz-Endpunkt; unbekannte IDs werden abgelehnt |
status | Auswahl | planned, done oder not_done (Standard: done) |
quantity | Zahl | Menge |
unit | Text | Einheit, z.B. m², Stück, m |
performed_on | Datum | Ausführungsdatum (Standard bei Einsatz-Massnahmen: Einsatzdatum) |
note | Text | Notiz |
site_external_id | Text | Nur im obersten measures-Block: Standort der Massnahme |
poi_external_id | Text | Nur im obersten measures-Block: Naturwert der Massnahme |
Massnahmen lassen sich innerhalb eines Einsatzes mitliefern oder – ohne Einsatz – im obersten measures-Block direkt an einen Standort oder einen Naturwert hängen.
Artbeobachtungen (observations)
| Feld | Typ | Beschreibung |
|---|---|---|
species_name | Text (Pflicht) | Name der Art |
taxonomic_group | Auswahl | flora, insects, birds, amphibians_reptiles, mammals, other |
count_estimate | Text | Geschätzte Anzahl, z.B. «ca. 20» |
observation_date | Datum | Format JJJJ-MM-TT (Standard: Einsatzdatum) |
notes | Text | Notizen |
5. Beispiel: Import
Anfrage
POST /api/public/v1/import
Authorization: Bearer bm_live_DEIN_SCHLUESSEL
Content-Type: application/json
{
"sites": [{
"external_id": "agn-site-01",
"name": "Magerwiese Sonnenhalde",
"site_type": "magerwiese",
"description": "Extensiv genutzte Wiese am Südhang",
"area_sqm": 2400,
"latitude": 47.242,
"longitude": 8.723,
"landowner_partner": "Gemeinde Muster",
"focus_species": ["Kuckuckslichtnelke", "Wiesenschaumkraut"],
"is_sensitive": false,
"active": true
}],
"pois": [{
"external_id": "agn-poi-14",
"site_external_id": "agn-site-01",
"name": "Nisthilfe Nr. 14",
"kind": "nisthilfe",
"detail": "Zielart: Wendehals",
"year_created": 2021,
"latitude": 47.2421,
"longitude": 8.7233,
"condition": "gut",
"is_active": true
}],
"events": [{
"external_id": "agn-event-2026-01",
"site_external_id": "agn-site-01",
"title": "Frühlingspflege",
"event_date": "2026-03-21",
"date_precision": "exact",
"participants_count": 8,
"duration_hours": 3,
"evidence_source": "protocol",
"external_url": "https://verein.ch/einsaetze/2026-01",
"notes": "Neophyten entfernt",
"measures": [{
"measure_id": "UUID_AUS_DEM_REFERENZ_ENDPUNKT",
"status": "done",
"quantity": 2400,
"unit": "m²",
"note": "Erste Mahd"
}],
"observations": [{
"species_name": "Kuckuckslichtnelke",
"taxonomic_group": "flora",
"count_estimate": "ca. 200",
"observation_date": "2026-03-21",
"notes": "Auf der ganzen Fläche"
}]
}],
"measures": [{
"measure_id": "UUID_AUS_DEM_REFERENZ_ENDPUNKT",
"poi_external_id": "agn-poi-14",
"status": "done",
"performed_on": "2026-02-10",
"note": "Nisthilfe gereinigt"
}]
}Antwort bei Erfolg
HTTP 200
{
"ok": true,
"result": {
"sites": { "created": 1, "updated": 0, "ids": { "agn-site-01": "INTERNE_UUID" } },
"pois": { "created": 1, "updated": 0, "ids": { "agn-poi-14": "INTERNE_UUID" } },
"events": { "created": 1, "updated": 0, "ids": { "agn-event-2026-01": "INTERNE_UUID" } },
"measures": { "created": 2 }
}
}Antwort bei ungültigen Daten
HTTP 400
{
"error": {
"code": "validation_error",
"message": "Die gelieferten Daten sind ungültig",
"fields": [
{ "path": "events.0.event_date", "message": "Invalid date" }
]
}
}Aufruf mit curl
curl -X POST https://DEINE-APP.lovable.app/api/public/v1/import \
-H "Authorization: Bearer bm_live_DEIN_SCHLUESSEL" \
-H "Content-Type: application/json" \
-d @import.json6. Verhalten bei wiederholter Lieferung
- Gleiche
external_idaktualisiert den bestehenden Datensatz – es entstehen keine Duplikate. - Nicht mitgesendete optionale Felder bleiben unverändert.
- Mitgesendete
measures- oderobservations-Listen innerhalb eines Einsatzes ersetzen die bisherigen API-importierten Untereinträge dieses Einsatzes vollständig; leere Listen löschen sie bewusst. Manuell in der App erfasste Untereinträge bleiben erhalten. - Der oberste
measures-Block ist eine vollständige Synchronisation: Alle zuvor per API gelieferten Massnahmen ohne Einsatz werden ersetzt. - Jeder Block ist eigenständig – ein Verein kann nur Standorte und Naturwerte liefern, nur Einsätze synchronisieren oder nur Massnahmen ergänzen.
- Jede Anfrage wird vollständig oder gar nicht übernommen – ein Fehler hinterlässt keine Teildaten.
7. Grenzen und Fehlercodes
- Maximal 100 Standorte, 500 Naturwerte, 100 Einsätze und 500 freie Massnahmen pro Anfrage, je 50 Massnahmen und 50 Beobachtungen pro Einsatz.
401 unauthorized– Schlüssel fehlt, ist ungültig oder wurde widerrufen.400 invalid_json– die Anfrage enthält kein gültiges JSON.400 validation_error– ungültige Felder; die Antwort nennt jeden Feldpfad.400 empty_payload– kein einziger Datensatz mitgesendet.422 import_failed– fachlicher Fehler, z.B. unbekannte Massnahme oder fremder Standort.