fepli
API resources

Offers

An offer (Angebot) is one activity of an edition: a course, an excursion, a workshop, run by one or more organisers on one or more dates. Offers are the one part of the API that is public: the published offers can be read without a token.

The offer model

Fields marked with a token are returned to authenticated callers only. Fields without a value are left out of responses.

Properties

  • Name
    uuid
    Type
    string
    Description

    The offer's identifier.

  • Name
    name
    Type
    string
    Description

    The title of the offer.

  • Name
    alias
    Type
    string
    Description

    A URL-safe version of the name.

  • Name
    edition
    Type
    reference
    Description

    The edition the offer belongs to.

  • Name
    hosts
    Type
    reference[]
    Description

    The organisers who run the offer.

  • Name
    status
    Type
    string[]
    Description

    The places of the workflow the offer is in: draft, finalized, reviewed, published, cancelled, completed. Usually one. A published offer keeps published when it is cancelled or completed, so a cancelled offer reads ["published", "cancelled"].

  • Name
    teaser
    Type
    string
    Description

    A one-line summary.

  • Name
    description
    Type
    string
    Description

    The full description, formatted as Markdown.

  • Name
    dates
    Type
    object[]
    Description

    The dates of the offer. Each has a uuid, a begin and usually an end timestamp, and for recurring dates an iCalendar recurrence rule (RRULE).

  • Name
    fee
    Type
    integer
    Description

    The fee in cents. Missing or 0 means the offer is free.

  • Name
    minAge
    Type
    integer
    Description

    The minimum age of participants, in years.

  • Name
    maxAge
    Type
    integer
    Description

    The maximum age of participants, in years.

  • Name
    minParticipants
    Type
    integer
    Description

    How many participants the offer needs to take place.

  • Name
    maxParticipants
    Type
    integer
    Description

    How many participants the offer takes. Missing when unlimited.

  • Name
    vacancies
    Type
    integer
    Description

    Places left: maxParticipants minus confirmed and waitlisted applications. Missing when places are unlimited.

  • Name
    fullyBooked
    Type
    boolean
    Description

    Whether no places are left.

  • Name
    requiresApplication
    Type
    boolean
    Description

    Whether participants have to apply. If not, they just turn up.

  • Name
    onlineApplication
    Type
    boolean
    Description

    Whether families can apply on the fepli website.

  • Name
    applicationDeadline
    Type
    timestamp
    Description

    The last moment to apply.

  • Name
    meetingPoint
    Type
    string
    Description

    A short label for where to meet, such as "Haupteingang Stadtpark".

  • Name
    meetingAddress
    Type
    string
    Description

    The street address of the meeting point.

  • Name
    meetingLat
    Type
    number
    Description

    The latitude of the meeting point (WGS 84).

  • Name
    meetingLng
    Type
    number
    Description

    The longitude of the meeting point (WGS 84).

  • Name
    bring
    Type
    string
    Description

    What participants should bring.

  • Name
    applyText
    Type
    string
    Description

    Extra information shown when applying, formatted as Markdown.

  • Name
    wheelchairAccessible
    Type
    boolean
    Description

    Whether the offer is wheelchair accessible.

  • Name
    accessibility
    Type
    string[]
    Description

    Further accessibility features.

  • Name
    categories
    Type
    reference[]
    Description

    The categories the offer is filed under.

  • Name
    url
    Type
    string
    Description

    The offer's page on the fepli website, where families apply.

  • Name
    media
    Type
    string[]
    Description

    Absolute URLs of the offer's images, scaled to at most 3000 × 3000 pixels.

  • Name
    createdAt
    Type
    timestamp
    Description

    When the offer was created.

  • Name
    modifiedAt
    Type
    timestamp
    Description

    When the offer was last changed.

  • Name
    publish
    Type
    string
    Access
    with a token
    Description

    public, or private_link for an offer that can only be reached through its private link.

  • Name
    comment
    Type
    string
    Access
    with a token
    Description

    An internal note, never shown publicly.

  • Name
    contact
    Type
    object[]
    Access
    with a token
    Description

    The contact persons, as entered: objects with name, email and phone.

  • Name
    collectDateOfBirth
    Type
    boolean
    Access
    with a token
    Description

    Whether the application form asks for the participant's date of birth.

  • Name
    disableOnlinePayment
    Type
    boolean
    Access
    with a token
    Description

    Whether online payment is switched off for this offer.

  • Name
    attendances
    Type
    object
    Access
    with a token
    Description

    How many applications the offer has, by state: confirmed, waitlisted, waiting, withdrawn and rejected. total counts every application except withdrawn and unfulfilled ones.

  • Name
    participantListRecipientEmails
    Type
    string[]
    Access
    with a token
    Description

    Extra e-mail addresses that receive the participant list.

  • Name
    applicationQuestions
    Type
    object[]
    Access
    with a token
    Description

    The extra questions of the application form, each with a uuid, the question, its type (yn yes/no, int number, txt text, file upload), whether it is required, and for uploads the accepted fileTypes (image, pdf).

  • Name
    variantOf
    Type
    reference
    Access
    with a token
    Description

    The offer this one is a variant of, for example another date of the same course.

  • Name
    variants
    Type
    reference[]
    Access
    with a token
    Description

    The variants of this offer. Create one with POST /offers/{uuid}/variants.

  • Name
    transitions
    Type
    string[]
    Access
    with a token
    Description

    The workflow transitions you may apply right now.

The offer workflow

An offer moves through the same states as in the admin. An organiser drafts it and submits it (finalize); the team reviews it (approve) and publishes it (publish). Apply a transition with POST /offers/{uuid}/transition.

TransitionFromToWho may apply it
finalizedraftfinalizedanyone who can see the offer
to_draftfinalizeddraftadmins; organisers if the edition lets them publish
approvefinalized, unless completedreviewedadmins; organisers if the edition lets them publish
unapprovereviewedfinalizedadmins; organisers if the edition lets them publish
publishreviewedpublishedadmins; organisers if the edition lets them publish
unpublishpublishedreviewedadmins; organisers if the edition lets them publish
cancelpublished and not cancelled, before its last date has endedadds cancelledadmins; organisers if the installation allows it
relaunchcancelled, before its last date has endedpublishedas for cancel
completepublished, after its last date has endedadds completedadmins; organisers who can see the offer

A completed offer can't be cancelled or relaunched any more.

To take a reviewed offer back to draft, apply unapprove and then to_draft. A reviewed offer lists to_draft_2 in transitions: that is the admin's name for the same step, and the API doesn't accept it yet.


GET/offers

List all offers

Returns a page of offers, ordered by their first date.

  • Without a token: the published, public offers of the editions that are online, with the public fields.
  • With a token: every offer you could open in the admin, in any state, with all fields. Admins see all offers; organiser users see their organisers' offers and offers shared with them. A token whose owner is neither an admin nor a member of an organiser sees no offers at all, not even the published ones: leave the token out to read those.

Optional filters

  • Name
    q
    Type
    string
    Description

    Only offers whose name contains this text.

  • Name
    edition
    Type
    string
    Description

    Only offers of this edition (UUID or alias).

  • Name
    host
    Type
    string
    Description

    Only offers of this organiser (UUID or alias).

  • Name
    category
    Type
    string
    Description

    Only offers in this category (UUID or alias).

  • Name
    status
    Type
    string
    Description

    Only offers in these workflow places, comma-separated: draft, finalized, reviewed, published, cancelled, completed. published also matches offers that were cancelled after publication.

  • Name
    from
    Type
    date
    Description

    Only offers with a date that begins on or after this day.

  • Name
    until
    Type
    date
    Description

    Only offers with a date that begins on or before this day. Combined with from, an offer with several dates matches if one date is on or after from and one (not necessarily the same) is on or before until.

  • Name
    modifiedSince
    Type
    timestamp
    Description

    Only offers changed since this moment.

  • Name
    sort
    Type
    string
    Description

    begin (default, the first date), name, createdAt or modifiedAt.

  • Name
    order
    Type
    string
    Description

    asc (default) or desc.

  • Name
    page, itemsPerPage
    Type
    integer
    Description

    See Pagination.

Request

GET·/offers
curl -G https://ferienpass-musterstadt.de/api/offers \
  -d edition=herbstferien-2026 \
  -d from=2026-10-12

Response

[
  {
    "uuid": "0192a4f1-6e3b-7c85-b1d2-8f4e6a9c3b03",
    "name": "Fahrradtour durch den Stadtpark",
    "alias": "fahrradtour-durch-den-stadtpark",
    "edition": {
      "uuid": "01913e5c-2b4a-7d10-9f3e-6a1c2e7b4d01",
      "name": "Herbstferien 2026",
      "alias": "herbstferien-2026"
    },
    "hosts": [
      {
        "uuid": "01905a7e-8c21-7b3f-a0d4-3e9f1c6b2a02",
        "name": "Stadtjugendring Musterstadt e.V.",
        "alias": "stadtjugendring-musterstadt"
      }
    ],
    "status": ["published"],
    "teaser": "Mit dem Rad durch den Park – mit Picknick am See.",
    "description": "Eine **geführte Fahrradtour** für Kinder ab 8 Jahren.",
    "dates": [
      {
        "uuid": "0192a4f2-0a11-7e6c-9d38-2b7f5c1e8a04",
        "begin": "2026-10-14T09:00:00+02:00",
        "end": "2026-10-14T12:00:00+02:00"
      }
    ],
    "fee": 750,
    "minAge": 8,
    "maxAge": 12,
    "maxParticipants": 15,
    "vacancies": 4,
    "fullyBooked": false,
    "requiresApplication": true,
    "onlineApplication": true,
    "applicationDeadline": "2026-09-30T23:59:59+02:00",
    "meetingPoint": "Haupteingang Stadtpark",
    "meetingAddress": "Parkstraße 1, 12345 Musterstadt",
    "meetingLat": 52.520008,
    "meetingLng": 13.404954,
    "bring": "Fahrrad und Helm",
    "wheelchairAccessible": false,
    "categories": [
      {
        "uuid": "018f2c3d-4e5f-7a6b-8c7d-9e0f1a2b3c12",
        "name": "Sport & Bewegung",
        "alias": "sport-bewegung"
      }
    ],
    "url": "https://ferienpass-musterstadt.de/angebote/herbstferien-2026/1C8wV6pQk2Tz9RfXh4MbNd-fahrradtour-durch-den-stadtpark",
    "media": [
      "https://ferienpass-musterstadt.de/assets/images/f/fahrradtour-3000x2000.jpg"
    ],
    "createdAt": "2026-08-03T10:12:44+02:00",
    "modifiedAt": "2026-09-15T16:40:02+02:00"
  }
]

GET/offers/{uuid}

Retrieve an offer

Returns one offer. The same visibility rules apply as for the list: without a token, only a published, public offer of an online edition can be retrieved. Anything else is a 404.

With a token, the offer includes the internal fields, among them the application counts and the transitions you may apply.

Request

GET·/offers/{uuid}
curl https://ferienpass-musterstadt.de/api/offers/0192a4f1-6e3b-7c85-b1d2-8f4e6a9c3b03 \
  -H "Authorization: Bearer $FEPLI_TOKEN"

Response (with a token, excerpt)

{
  "uuid": "0192a4f1-6e3b-7c85-b1d2-8f4e6a9c3b03",
  "name": "Fahrradtour durch den Stadtpark",
  "status": ["published"],
  "…": "…",
  "publish": "public",
  "comment": "Leihräder beim ADFC angefragt.",
  "contact": [
    {
      "name": "Jonas Becker",
      "email": "j.becker@sjr-musterstadt.de",
      "phone": "0123 456789"
    }
  ],
  "collectDateOfBirth": false,
  "disableOnlinePayment": false,
  "attendances": {
    "confirmed": 11,
    "waitlisted": 0,
    "waiting": 2,
    "withdrawn": 1,
    "rejected": 0,
    "total": 13
  },
  "participantListRecipientEmails": [],
  "applicationQuestions": [
    {
      "uuid": "0192a4f4-1b2c-7d3e-8f4a-5b6c7d8e9f13",
      "question": "Kann Ihr Kind sicher Fahrrad fahren?",
      "type": "yn",
      "required": true,
      "fileTypes": []
    }
  ],
  "variants": [],
  "transitions": ["cancel", "unpublish"]
}

POST/offers

Create an offer

Creates an offer in the state draft. Admins can create offers in any edition. Organiser users can create them for their own organisers, in editions whose editing phase is running right now.

When a person creates the offer, they receive its participant list. When an organiser user belongs to exactly one organiser, that organiser is added automatically. Send contact to name the contact persons; the API doesn't fill it in for you.

Required attributes

  • Name
    name
    Type
    string
    Description

    The title of the offer.

  • Name
    edition
    Type
    string
    Description

    The edition, as UUID or alias. Organiser users must name one; without it the answer is 403.

Optional attributes

  • Name
    hosts
    Type
    string[]
    Description

    Organisers, as UUIDs or aliases. Organiser users may only name their own.

  • Name
    dates
    Type
    object[]
    Description

    Dates, each with begin, and optionally end and recurrence.

  • Name
    categories
    Type
    string[]
    Description

    Categories, as UUIDs or aliases.

  • Name
    publish
    Type
    string
    Description

    Send public (the default). The API doesn't accept private_link yet; to publish an offer through its private link only, set that in the admin.

  • Name
    contact
    Type
    object[]
    Description

    Contact persons: objects with name, email and phone.

  • Name
    participantListRecipientEmails
    Type
    string[]
    Description

    Extra recipients of the participant list.

You can also send teaser, description, fee, minAge, maxAge, minParticipants, maxParticipants, requiresApplication, onlineApplication, applicationDeadline, meetingPoint, meetingAddress, meetingLat, meetingLng, bring, applyText, wheelchairAccessible, accessibility, comment, collectDateOfBirth and disableOnlinePayment, as described in the model.

Ages range from 0 to 99, fees and participant numbers can't be negative, and short texts such as meetingPoint, bring, applyText and comment are limited to 255 characters.

Request

POST·/offers
curl -X POST https://ferienpass-musterstadt.de/api/offers \
  -H "Authorization: Bearer $FEPLI_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Töpfern für Anfänger",
    "edition": "herbstferien-2026",
    "hosts": ["stadtjugendring-musterstadt"],
    "dates": [
      { "begin": "2026-10-20T14:00:00+02:00", "end": "2026-10-20T16:30:00+02:00" }
    ],
    "fee": 500,
    "minAge": 6,
    "maxAge": 10,
    "maxParticipants": 8,
    "requiresApplication": true,
    "onlineApplication": true,
    "categories": ["kreativ"]
  }'

Response (201 Created, excerpt)

{
  "uuid": "0193c8a2-5d6e-7f70-9a8b-1c2d3e4f5a14",
  "name": "Töpfern für Anfänger",
  "alias": "toepfern-fuer-anfaenger",
  "status": ["draft"],
  "…": "…",
  "transitions": ["finalize"]
}

PATCH/offers/{uuid}

Update an offer

Changes an offer. Send only the attributes you want to change. The attributes are the same as for creating an offer. null clears a field, except for name, edition, hosts, dates, categories, publish and the yes/no fields, which ignore it. An empty body is a 422.

Dates are replaced as a whole when you send dates. To keep an existing date, include its uuid; dates you leave out are deleted, and dates without a uuid are added.

Admins can change any offer. Organiser users can change their offers until they are reviewed or published, and only while the edition is open for editing (see the edition's editableForHosts). Otherwise the answer is 403.

Request

PATCH·/offers/{uuid}
curl -X PATCH https://ferienpass-musterstadt.de/api/offers/0192a4f1-6e3b-7c85-b1d2-8f4e6a9c3b03 \
  -H "Authorization: Bearer $FEPLI_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "maxParticipants": 18,
    "dates": [
      {
        "uuid": "0192a4f2-0a11-7e6c-9d38-2b7f5c1e8a04",
        "begin": "2026-10-14T09:00:00+02:00",
        "end": "2026-10-14T12:30:00+02:00"
      },
      { "begin": "2026-10-16T09:00:00+02:00", "end": "2026-10-16T12:30:00+02:00" }
    ]
  }'

The response holds the changed offer.


DELETE/offers/{uuid}

Delete an offer

Deletes an offer with its applications. Responds with 204 No Content.

The deletion is refused with 409 while a paid receipt refers to one of the offer's applications. Reverse the receipt first, or cancel the offer instead. Organiser users can only delete offers that have no applications yet, while the edition is open for editing.

If the offer has variants, the next one takes its place as the main offer.

Request

DELETE·/offers/{uuid}
curl -X DELETE https://ferienpass-musterstadt.de/api/offers/0193c8a2-5d6e-7f70-9a8b-1c2d3e4f5a14 \
  -H "Authorization: Bearer $FEPLI_TOKEN"

POST/offers/{uuid}/transition

Apply a transition

Moves the offer through its workflow. The offer's transitions list the ones you may apply right now. Anything else, including a transition you lack the permission for, is a 409 that names the possible transitions.

cancel and relaunch e-mail the families who applied, the same as in the admin.

Required attributes

  • Name
    transition
    Type
    string
    Description

    One of finalize, to_draft, approve, unapprove, publish, unpublish, cancel, relaunch, complete.

Optional attributes

  • Name
    notifyText
    Type
    string
    Description

    For cancel and relaunch: the text of the e-mail to the families. Leave it out to use the configured text.

Request

POST·/offers/{uuid}/transition
curl -X POST https://ferienpass-musterstadt.de/api/offers/0192a4f1-6e3b-7c85-b1d2-8f4e6a9c3b03/transition \
  -H "Authorization: Bearer $FEPLI_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "transition": "cancel",
    "notifyText": "Leider muss die Fahrradtour wegen Sturmwarnung ausfallen."
  }'

Response (excerpt)

{
  "uuid": "0192a4f1-6e3b-7c85-b1d2-8f4e6a9c3b03",
  "status": ["published", "cancelled"],
  "…": "…",
  "transitions": ["relaunch", "unpublish"]
}

POST/offers/{uuid}/copy

Copy an offer

Copies an offer into a new offer in the state draft, like Angebot kopieren in the admin. Responds with 201 Created and the copy. The original is left as it is.

Without edition, the copy is made in the offer's own edition, dates included. With edition, it is made in that edition, and the dates and the application deadline stay behind: they belonged to the old holidays. Add the new ones with PATCH /offers/{uuid}. This also applies when you name the offer's own edition.

You need to see the original (404 otherwise) and be allowed to create an offer in the edition the copy lands in: admins always are, organiser users while that edition's editing phase is running (403 otherwise). An edition that doesn't exist is a 422.

What a copy carries over

The copy takes the texts and settings of the original: name, teaser, description, fee, ages, participant numbers, application settings and questions, meeting point, what to bring, accessibility, categories, organisers, contact persons, recipients of the participant list, the internal comment, publish and consent forms. Images and attachments are carried over too; the copy refers to the same files.

It doesn't take what the original has gathered: applications, comments, the history, variants, and the accounts the offer was shared with directly. A copy is always an offer of its own, even when the original is a variant. It gets a new uuid and its own private link. Its createdAt and modifiedAt are the moment of the copy.

Optional attributes

  • Name
    edition
    Type
    string
    Description

    The edition to copy into, as UUID or alias. Leave it out to copy within the offer's own edition, dates included.

The request needs a JSON body: send {} to copy within the edition.

Copying a whole edition

There is no call for that. List the offers with GET /offers?edition=… and copy each into the new edition. The admin's Aus Vorjahr kopieren leaves out the variants (offers with variantOf), so they don't turn into offers of their own; do the same if you want its result.

Request

POST·/offers/{uuid}/copy
curl -X POST https://ferienpass-musterstadt.de/api/offers/0192a4f1-6e3b-7c85-b1d2-8f4e6a9c3b03/copy \
  -H "Authorization: Bearer $FEPLI_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"edition": "herbstferien-2027"}'

Response (201 Created, excerpt)

{
  "uuid": "019a3b1e-7c2d-7e4f-8a5b-6c7d8e9f0a21",
  "name": "Fahrradtour durch den Stadtpark",
  "edition": {
    "uuid": "019a3b10-2c3d-7e4f-9a5b-6c7d8e9f0a20",
    "name": "Herbstferien 2027",
    "alias": "herbstferien-2027"
  },
  "status": ["draft"],
  "dates": [],
  "fee": 750,
  "…": "…",
  "attendances": {
    "confirmed": 0,
    "waitlisted": 0,
    "waiting": 0,
    "withdrawn": 0,
    "rejected": 0,
    "total": 0
  },
  "transitions": ["finalize"]
}

POST/offers/{uuid}/variants

Create a variant

Creates a variant of an offer: the same activity for another group of participants, usually on other dates. Like Neuen Termin erstellen in the admin. Responds with 201 Created and the new variant.

A variant is a copy in the state draft, in the same edition and with the same dates, that is linked to the main offer: its variantOf names the main offer, and the main offer lists it in variants. Change its dates with PATCH /offers/{uuid}. A variant of a variant is linked to the same main offer.

The request has no body. The same permissions apply as for a copy: 404 if you can't see the offer, 403 if you may not create an offer in its edition.

Request

POST·/offers/{uuid}/variants
curl -X POST https://ferienpass-musterstadt.de/api/offers/0192a4f1-6e3b-7c85-b1d2-8f4e6a9c3b03/variants \
  -H "Authorization: Bearer $FEPLI_TOKEN"

Response (201 Created, excerpt)

{
  "uuid": "019a3b2f-1d2e-7f30-8b4c-5d6e7f8a9b22",
  "name": "Fahrradtour durch den Stadtpark",
  "status": ["draft"],
  "dates": [
    {
      "uuid": "019a3b2f-1d2f-7a41-9c5d-6e7f8a9b0c23",
      "begin": "2026-10-14T09:00:00+02:00",
      "end": "2026-10-14T12:00:00+02:00"
    }
  ],
  "…": "…",
  "variantOf": {
    "uuid": "0192a4f1-6e3b-7c85-b1d2-8f4e6a9c3b03",
    "name": "Fahrradtour durch den Stadtpark",
    "alias": "fahrradtour-durch-den-stadtpark"
  }
}

POST/offers/{uuid}/refill

Refill from the waiting list

Fills the free places of an offer from its waiting list, like Teilnahmeliste auffüllen in the admin. Families move up in the order of the waiting list (first come, first served), whatever application procedure the edition uses. Each family that moves up is confirmed, and its fee falls due as for any confirmation.

The work is done in the background, shortly after the call. The API answers 202 Accepted with the offer as it is at that moment; fetch its participant list a little later to see who moved up.

To add places, raise maxParticipants with PATCH /offers/{uuid}, then call this endpoint. That is what Anzahl Plätze erhöhen does in the admin.

The call is refused with 409 when there is nothing to do: the offer has no dates or its first date has begun, nobody is on the waiting list, or every place is taken. It needs the permission to change the offer: admins always have it; organiser users only until the offer is reviewed or published, while the edition is open for editing (403 otherwise).

Optional attributes

The request needs a JSON body: send {} for the defaults.

  • Name
    notify
    Type
    boolean
    Description

    E-mail the families who move up that they have a place. Defaults to false.

  • Name
    commit
    Type
    boolean
    Description

    Record the confirmations now. Defaults to true. With false, they are held back until the edition's decisions are committed; notify then has to be false too (422 otherwise).

Request

POST·/offers/{uuid}/refill
curl -X POST https://ferienpass-musterstadt.de/api/offers/0192a4f1-6e3b-7c85-b1d2-8f4e6a9c3b03/refill \
  -H "Authorization: Bearer $FEPLI_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"notify": true}'

Response (202 Accepted, excerpt)

{
  "uuid": "0192a4f1-6e3b-7c85-b1d2-8f4e6a9c3b03",
  "maxParticipants": 18,
  "…": "…",
  "attendances": {
    "confirmed": 15,
    "waitlisted": 5,
    "waiting": 0,
    "withdrawn": 1,
    "rejected": 0,
    "total": 20
  }
}

Was this page helpful?