fepli
EntwicklerREST API

Konventionen

Jeder Endpunkt der fepli-API folgt denselben Regeln für Kennungen, Datumsangaben, Geld, Filter und Schreibzugriffe. Sie werden hier einmal erklärt, damit die Referenz der Ressourcen kurz bleiben kann.

Anfragen und Antworten

Die API spricht nur JSON. Antworten sind application/json, Fehler sind application/problem+json (siehe Fehler).

Anfragen mit einem Body (POST, PATCH) müssen Content-Type: application/json senden. Bei PATCH funktioniert auch application/merge-patch+json. Ein Request-Body ohne JSON-Content-Type wird mit 415 Unsupported Media Type abgelehnt.

Eine Schreibanfrage

curl -X PATCH https://example.fepli.eu/api/offers/0192a4f1-6e3b-7c85-b1d2-8f4e6a9c3b03 \
  -H "Authorization: Bearer $FEPLI_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"maxParticipants": 15}'

Die Feldnamen sind englisch. Inhalte wie Namen und Beschreibungen von Angeboten kommen so zurück, wie sie eingegeben wurden, meist auf Deutsch.

Kennungen

Jeder Datensatz hat eine UUID (RFC 4122), die als uuid zurückkommt:

0192a4f1-6e3b-7c85-b1d2-8f4e6a9c3b03

Die URLs des Admin-Panels enthalten dieselbe UUID in einer kürzeren Base58-Form (22 Zeichen, zum Beispiel 1C8wV6pQk2Tz9RfXh4MbNd). Die API akzeptiert beide Formen überall, wo sie eine Kennung liest: in Pfaden, Filtern und Request-Bodys. Sie können also die einfügen, die Sie zur Hand haben. Antworten verwenden immer die Form nach RFC 4122.

Manche Datensätze können in Filtern und Request-Bodys auch über etwas Einprägsameres benannt werden:

DatensatzEbenfalls akzeptiert
Saisonihr alias, z. B. herbstferien-2026
Veranstalter:inihr alias, z. B. stadtjugendring-elmsbrueck
Kategorieihr alias, z. B. sport-bewegung
Kontoseine E-Mail-Adresse

Pfade nehmen eine UUID (in beiden Formen), nie einen Alias: /editions/herbstferien-2026 funktioniert nicht, ?edition=herbstferien-2026 funktioniert.

Referenzen

Verweist ein Datensatz auf einen anderen, bettet er eine kleine Referenz ein, die genug enthält, um den Datensatz anzuzeigen und abzurufen:

Eine Referenz

{
  "uuid": "01913e5c-2b4a-7d10-9f3e-6a1c2e7b4d01",
  "name": "Herbstferien 2026",
  "alias": "herbstferien-2026"
}
  • Name
    uuid
    Typ
    string
    Beschreibung

    Die Kennung, mit der Sie den vollständigen Datensatz abrufen.

  • Name
    name
    Typ
    string
    Beschreibung

    Ein Anzeigename: der vollständige Name einer Person, der Titel eines Angebots, die Nummer eines Belegs. Fehlt, wenn die Daten der Person maskiert sind.

  • Name
    alias
    Typ
    string
    Beschreibung

    Der URL-taugliche Alias, bei Datensätzen, die einen haben (Saisons, Veranstalter:innen, Angebote, Kategorien).

Manche Listen verwandter Datensätze enthalten stattdessen reine UUID-Strings, zum Beispiel receipts bei einer Anmeldung.

Leere Felder fehlen

Felder, deren Wert null ist, werden in Antworten ausgelassen. Ein Angebot ohne Treffpunkt hat schlicht keinen Schlüssel meetingPoint. Behandeln Sie ein fehlendes Feld wie null.

Listen, die für Sie gelten, sind immer vorhanden, leere kommen als [] zurück. Felder, die Sie nicht sehen dürfen, etwa die internen Felder eines Angebots ohne Token, fehlen ganz. Booleans und Zahlen mit einem Standardwert sind immer vorhanden.

Eine Ausnahme sind einige verschachtelte Listen einfacher Werte, etwa die tasks einer Saison, die items eines Belegs und die bookEntries einer Debitor:in: Dort erscheinen leere Werte als null.

Datum und Uhrzeit

Zeitstempel folgen ISO 8601 mit Offset, in der Ortszeit der Organisation (Europe/Berlin):

2026-10-14T09:00:00+02:00

Wenn Sie einen Zeitstempel senden, geben Sie den Offset an. Werte nur mit Datum (etwa das dateOfBirth einer Teilnehmer:in) werden als 2015-04-12 akzeptiert.

Datumsfilter wie from, until oder modifiedSince akzeptieren ein Datum (2026-10-01) oder einen vollständigen Zeitstempel. Ein nicht lesbares Datum ist ein 400.

Geld

Beträge sind ganze Zahlen in Cent. fee: 750 sind 7,50 €. Negative Beträge erscheinen bei Stornierungen und in Freien Buchungen: siehe Belege und Debitor:innen.

Filter

Endpunkte für Sammlungen nehmen ihre Filter als Query-Parameter. Jede Ressource nennt ihre eigenen.

curl "https://example.fepli.eu/api/attendances?edition=herbstferien-2026&status=confirmed,waitlisted&paid=false" \
  -H "Authorization: Bearer $FEPLI_TOKEN"
  • Mehrere Filter werden kombiniert: Ein Datensatz muss alle erfüllen.
  • Mehrere Werte eines Filters werden, wo der Filter es erlaubt, durch Kommas getrennt und mit ODER kombiniert: status=confirmed,waitlisted.
  • Booleans sind true oder false (1/0 und yes/no funktionieren ebenfalls).
  • Die Freitextsuche (q) findet jeden Teil der Felder, die die Ressource nennt, ohne Beachtung der Groß- und Kleinschreibung.
  • Ein fehlerhafter Wert, etwa ein Datum, das sich nicht lesen lässt, ein true, das kein Boolean ist, oder ein unbekanntes sort, ist ein 400 Bad Request, dessen detail den Parameter nennt.
  • Eine Referenz, die nichts findet, etwa ?edition= mit einem Alias, den es nicht gibt, ist kein Fehler. Die Antwort ist eine leere Liste. (Eine Ausnahme ist der Filter offer der Anmeldungen: Ein unbekanntes Angebot ist ein 404.)
  • Unbekannte Parameter werden ignoriert.

Schreibzugriffe

MethodeZweckErfolg
POST /thingseinen Datensatz anlegen201 Created mit dem neuen Datensatz
PATCH /things/{uuid}einen Datensatz ändern200 OK mit dem geänderten Datensatz
DELETE /things/{uuid}einen Datensatz löschen204 No Content
POST /things/{uuid}/actioneine Aktion: ein Übergang, eine Stornierung, ein Widerruf200 OK mit dem Datensatz, der dabei entsteht
POST /things/{uuid}/actioneine Aktion, die einen neuen Datensatz erzeugt: eine Kopie, eine Variante, die Übertragung auf ein anderes Angebot201 Created mit dem neuen Datensatz
POST /things/{uuid}/actioneine Aktion, die im Hintergrund läuft: eine Warteliste auffüllen, Entscheidungen festschreiben202 Accepted mit dem Datensatz, wie er jetzt ist

So funktioniert PATCH

PATCH wendet nur die Schlüssel an, die Sie senden:

  • Ein Schlüssel, den Sie weglassen, bleibt unberührt.
  • Ein Schlüssel, den Sie als null senden, leert das Feld.
  • Eine Liste, die Sie senden (zum Beispiel dates, hosts oder categories eines Angebots), ersetzt die ganze Liste.
  • Ein leerer Body ist ein 422: Es gibt nichts zu ändern. (Saisons sind die Ausnahme und kommen unverändert zurück.)

Den Beitrag ändern, den Treffpunkt leeren

curl -X PATCH https://example.fepli.eu/api/offers/0192a4f1-6e3b-7c85-b1d2-8f4e6a9c3b03 \
  -H "Authorization: Bearer $FEPLI_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"fee": 500, "meetingPoint": null}'

Felder, die immer einen Wert haben müssen, etwa ein Name oder die Saison eines Angebots, ignorieren null. Jede Ressource nennt sie.

Validierung

Schreibzugriffe werden nach denselben Regeln validiert wie die Formulare des Admin-Panels. Ungültige Eingaben ergeben ein 422 Unprocessable Entity. Sein detail enthält immer eine Zeile pro Problem, jeweils beginnend mit dem Feld:

422 Unprocessable Entity

{
  "type": "/validation_errors/04b91c99-a946-4221-afc5-e65ebac401eb",
  "title": "An error occurred",
  "status": 422,
  "detail": "maxAge: This value should be between 0 and 99.",
  "violations": [
    {
      "propertyPath": "maxAge",
      "message": "This value should be between 0 and 99.",
      "code": "04b91c99-a946-4221-afc5-e65ebac401eb"
    }
  ]
}

Ist ein Wert fehlerhaft oder außerhalb des zulässigen Bereichs, wie oben, nennt die Antwort jedes Problem zusätzlich in violations. Ist eine Anfrage korrekt aufgebaut, ergibt aber für den Datensatz keinen Sinn, etwa eine Saison, die es nicht gibt, oder ein Betrag über dem Beitrag, erhalten Sie nur das detail. Wenn Sie detail lesen, sind Sie in beiden Fällen gut bedient.

Workflows

Angebote und Anmeldungen durchlaufen Status, genau wie im Admin-Panel. Sie setzen ihren Status nicht direkt. Stattdessen wenden Sie mit POST …/{uuid}/transition einen Übergang an:

curl -X POST https://example.fepli.eu/api/attendances/0192d0e8-3a4b-7c5d-9e6f-7a8b9c0d1e07/transition \
  -H "Authorization: Bearer $FEPLI_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"transition": "confirm", "notify": true}'

Jedes Angebot und jede Anmeldung nennt ihre möglichen Übergänge in transitions. Bei Angeboten berücksichtigt die Liste bereits Ihre Berechtigungen. Bei Anmeldungen spiegelt sie nur den Status. Versuchen Sie einen Übergang, der nicht möglich ist, lautet die Antwort 409 Conflict, und sie nennt die möglichen:

409 Conflict

{
  "type": "/errors/409",
  "title": "An error occurred",
  "status": 409,
  "detail": "The transition \"noshow\" is not possible from \"waitlisted\". Possible: confirm, withdraw, reset, reject, unfulfill, participated."
}

Die Übergänge haben dieselben Nebenwirkungen wie im Admin-Panel: E-Mails an Familien (wenn Sie sie anfordern), neu sortierte Teilnahmelisten, aktualisierte Zahlungsdaten.

Caching

Antworten auf authentifizierte Anfragen tragen Cache-Control: private, no-store. Sie sind die Sicht einer einzelnen Person und dürfen nie von einem gemeinsamen Cache gespeichert werden. Anonyme Lesezugriffe auf die öffentlichen Angebote bleiben cachebar.

War diese Seite hilfreich?