← ChangelogBreaking

Events: private calendars stay private, plus series, agendas, attendees and tickets

2026.10.14-api-events
The Forumulate team
2 min read
apievents

Changed

Public events routes now check that the space is public. Before this release, every route under /public/orgs/{orgId}/spaces/{spaceId}/events returned events from any EVENTS space, even a private one. That covered the list, a single event, calendar.ics, the per-event .ics and the feeds. These routes now answer 404 unless the space is public or the request carries a live share token. Pass the token as ?share=<token>; the per-space share cookie a reader already holds also works. The same check now covers the new agenda, attendee, session .ics and series routes. When a calendar file is served on a share token, it is sent as private, no-store. If you read events from a private space through the public routes, add the space's share token.

An event has a lifecycle. Events can be POSTPONED as well as cancelled, with a reason, and keep previousStartsAt. A postponed or cancelled event stays readable. RSVPing to one answers 409. Each event carries phase (upcoming, live or past), and the list takes ?scope=upcoming|past, ?mode=, ?from=, ?to=, ?tag= and ?q=. The list's page.total gives the count. .ics files now carry STATUS, SEQUENCE and a time zone.

Join links can be for attendees only. With joinLinkVisibility: attendees, the join link is removed from the public API, the page and the .ics. An attendee with a going answer gets it as joinUrl on GET/PUT …/rsvp.

Added

Series. An event can repeat by a rule. Each date is its own event, and the rule is read in the event's own time zone. seriesScope: following applies an edit to every date still to come. Public reads: GET …/events/{handle}/series and series.ics (with RRULE and EXDATE).

Agendas and speakers.

  • Staff CRUD: /orgs/{orgId}/spaces/{spaceId}/events/{handle}/sessions and /event-speakers.

  • A signed-in reader's own agenda: …/events/{handle}/my-agenda.

  • Public reads: GET /public/…/events/{handle}/agenda (sessions and speakers in one read) and a calendar file per session at …/sessions/{session}/calendar.ics.

Attendees.

  • RSVPs can wait for staff approval (pending) and bring guests, and the capacity counts seats.

  • Registration questions use the forms field model.

  • Staff can list attendees, export attendees.csv, check people in, approve, decline and message them.

  • A space can opt in to email-only RSVPs with double opt-in (POST /public/…/events/{handle}/rsvp, /confirm, /cancel) and to a public "who's going" list.

  • Space settings live at …/event-attendance.

  • Email-only RSVPs have their own privacy request flow at POST /public/…/event-rsvps/privacy.

Tickets. Paid tiers, promo codes, orders and refunds. The public flow is GET /public/…/events/{handle}/tickets, then quote, checkout and confirm. Payments go to the org's own Stripe; see the payments release.

Reminders and notices. GET/PUT /orgs/{orgId}/spaces/{spaceId}/event-notices configures confirmations, reminders ("1d,1h") and the organizer digest. Space settings win over org settings. Webhooks: event.published, event.updated, event.cancelled, rsvp.created, rsvp.updated and rsvp.deleted.

Feeds and subscribe. …/events/rss.xml, atom.xml and feed.json, plus POST …/events/subscribe for email announcements. calendar.ics takes ?tag=. POST /orgs/…/events/{handle}/duplicate copies an event.