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: 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}: 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 - expiryDate 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 expiryDate: type: string format: date description: Date after which event data is deleted. Must be in the future. example: "2026-06-15" CreateEventResponse: type: object required: - eventToken - organizerToken - title - dateTime - timezone - expiryDate 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" expiryDate: type: string format: date example: "2026-06-15" GetEventResponse: type: object required: - eventToken - title - dateTime - timezone - attendeeCount - expired 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 expired: type: boolean description: Whether the event's expiry date has passed example: false 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" 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