openapi: 3.1.0 info: title: fete API description: Privacy-focused event announcements and RSVPs version: 0.1.0 license: name: GPL-3.0-or-later identifier: GPL-3.0-or-later servers: - url: /api paths: /events: post: operationId: createEvent summary: Create a new event tags: - events requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/CreateEventRequest" responses: "201": description: Event created successfully content: application/json: schema: $ref: "#/components/schemas/CreateEventResponse" "400": description: Validation failed content: application/problem+json: schema: $ref: "#/components/schemas/ValidationProblemDetail" /events/{token}/rsvps/{rsvpToken}: delete: operationId: cancelRsvp summary: Cancel RSVP description: | Permanently deletes an RSVP identified by the RSVP token. Idempotent: returns 204 whether the RSVP existed or not. tags: - events parameters: - name: token in: path required: true schema: type: string format: uuid description: Event token (UUID) - name: rsvpToken in: path required: true schema: type: string format: uuid description: RSVP token (UUID) identifying the attendance to cancel responses: "204": description: > RSVP successfully cancelled (or was already cancelled). No response body. "500": description: Internal server error /events/{token}/rsvps: post: operationId: createRsvp summary: Submit an RSVP for an event tags: - events parameters: - name: token in: path required: true schema: type: string format: uuid description: Public event token requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/CreateRsvpRequest" responses: "201": description: RSVP created successfully content: application/json: schema: $ref: "#/components/schemas/CreateRsvpResponse" "400": description: Validation failed (e.g. blank name) content: application/problem+json: schema: $ref: "#/components/schemas/ValidationProblemDetail" "404": description: Event not found content: application/problem+json: schema: $ref: "#/components/schemas/ProblemDetail" "409": description: Event has expired — RSVPs no longer accepted content: application/problem+json: schema: $ref: "#/components/schemas/ProblemDetail" /events/{token}/attendees: get: operationId: getAttendees summary: Get attendee list for an event (organizer only) tags: - events parameters: - name: token in: path required: true schema: type: string format: uuid description: Public event token - name: organizerToken in: query required: true schema: type: string format: uuid description: Organizer token for authorization responses: "200": description: Attendee list content: application/json: schema: $ref: "#/components/schemas/GetAttendeesResponse" "403": description: Invalid organizer token content: application/problem+json: schema: $ref: "#/components/schemas/ProblemDetail" "404": description: Event not found content: application/problem+json: schema: $ref: "#/components/schemas/ProblemDetail" /events/{token}: get: operationId: getEvent summary: Get public event details by token tags: - events parameters: - name: token in: path required: true schema: type: string format: uuid description: Public event token responses: "200": description: Event found content: application/json: schema: $ref: "#/components/schemas/GetEventResponse" "404": description: Event not found content: application/problem+json: schema: $ref: "#/components/schemas/ProblemDetail" components: schemas: CreateEventRequest: type: object required: - title - dateTime - timezone properties: title: type: string minLength: 1 maxLength: 200 description: type: string maxLength: 2000 dateTime: type: string format: date-time description: Event date and time with UTC offset (ISO 8601) example: "2026-03-15T20:00:00+01:00" timezone: type: string description: IANA timezone of the organizer example: "Europe/Berlin" location: type: string maxLength: 500 CreateEventResponse: type: object required: - eventToken - organizerToken - title - dateTime - timezone properties: eventToken: type: string format: uuid description: Public token for the event URL example: "a1b2c3d4-e5f6-7890-abcd-ef1234567890" organizerToken: type: string format: uuid description: Secret token for organizer access example: "f9e8d7c6-b5a4-3210-fedc-ba9876543210" title: type: string example: "Summer BBQ" dateTime: type: string format: date-time example: "2026-03-15T20:00:00+01:00" timezone: type: string description: IANA timezone of the organizer example: "Europe/Berlin" GetEventResponse: type: object required: - eventToken - title - dateTime - timezone - attendeeCount properties: eventToken: type: string format: uuid description: Public event token example: "a1b2c3d4-e5f6-7890-abcd-ef1234567890" title: type: string description: Event title example: "Summer BBQ" description: type: string description: Event description (absent if not set) example: "Bring your own drinks!" dateTime: type: string format: date-time description: Event date/time with organizer's UTC offset example: "2026-03-15T20:00:00+01:00" timezone: type: string description: IANA timezone name of the organizer example: "Europe/Berlin" location: type: string description: Event location (absent if not set) example: "Central Park, NYC" attendeeCount: type: integer minimum: 0 description: Number of confirmed attendees (attending=true) example: 12 CreateRsvpRequest: type: object required: - name properties: name: type: string minLength: 1 maxLength: 100 description: Guest's display name example: "Max Mustermann" CreateRsvpResponse: type: object required: - rsvpToken - name properties: rsvpToken: type: string format: uuid description: Token identifying this RSVP (store client-side for future updates) example: "d4e5f6a7-b8c9-0123-4567-890abcdef012" name: type: string description: Guest's display name as stored example: "Max Mustermann" GetAttendeesResponse: type: object required: - attendees properties: attendees: type: array items: $ref: "#/components/schemas/Attendee" example: - name: "Alice" - name: "Bob" Attendee: type: object required: - name properties: name: type: string minLength: 1 maxLength: 100 example: "Alice" ProblemDetail: type: object properties: type: type: string format: uri default: "about:blank" title: type: string status: type: integer detail: type: string instance: type: string format: uri additionalProperties: true ValidationProblemDetail: allOf: - $ref: "#/components/schemas/ProblemDetail" - type: object properties: fieldErrors: type: array items: type: object required: - field - message properties: field: type: string message: type: string