Events: private calendars stay private, plus series, agendas, attendees and tickets
2026.10.14-api-eventsChanged
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}/sessionsand/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.