Skip to main content

Events API

StatusImplementation
✅ Shippedsrc/feats/events/
PostGIS Required

Events use PostGIS for geo queries. The extension is enabled in migration 0003_overconfident_redwing.sql.

Create and manage events. Events are the primary social object: users create them, invite friends as co-authors, and other users form like groups to apply.

See also: Event lifecycle, Feed algorithm, Events model.

All endpoints require Authorization: Bearer <supabase-access-token>.

Endpoints​

MethodPathDescription
POST/eventsCreate event (in draft)
GET/eventsBrowse events feed
GET/events/:idGet event details
PATCH/events/:idUpdate event (before start_at)
DELETE/events/:idSoft-delete
POST/events/:id/restoreRestore a soft-deleted event
POST/events/:id/publishdraft → published
POST/events/:id/cancelpublished | started → cancelled
POST/events/:id/authorsInvite a friend as co-author
GET/events/:id/authorsList authors
DELETE/events/:id/authors/:userIdRemove a co-author (creator only)
POST/events/:id/likeCreate a solo or group like
GET/events/:id/likesList like groups for the event
GET/events/mineList owned and accepted co-organized events
PUT/events/:id/coverSet an uploaded cover
DELETE/events/:id/coverRemove the cover
POST/events/:id/authors/acceptAccept a co-author invitation
POST/events/:id/authors/refuseRefuse a co-author invitation

Create event​

POST /events
Authorization: Bearer <token>
Content-Type: application/json

{
"title": "Saturday Night Party",
"description": "Join us for drinks!",
"type": "party",
"visibility": "public",
"startAt": "2026-05-15T20:00:00Z",
"endAt": "2026-05-16T02:00:00Z",
"latitude": 40.7128,
"longitude": -74.006,
"capacity": 50
}
FieldTypeRequiredNotes
titlestring✅Max 100 characters
descriptionstringMax 2000 characters
typeenum✅Event taxonomy from OpenAPI; includes many values plus other
visibilityenum✅public, private
startAtISO8601✅
endAtISO8601
latitudenumber✅WGS84
longitudenumber✅WGS84
capacityintDefault 200, max 10000; creator + authors don't count
consentThresholdintDeprecated compatibility field; no longer affects approval
imageKeystringUploaded media key for a cover
imageUrlstringDeprecated external cover URL
address, citystringDisplay location text

Response​

{
"id": "uuid",
"creatorId": "uuid",
"status": "draft",
"...": "..."
}

Feed​

GET /events?lat=40.7128&lng=-74.006&radius=5000
Authorization: Bearer <token>
QueryDescription
lat, lngRequired when filtering by location
radiusMetres (100-50000, default 5000) — uses ST_DWithin on geography(Point, 4326)
typeFilter by event type
friendsOnlyOnly events created by friends
cursor, limitPagination (limit 1-100, default 20)
startDate, endDateISO date range filter
maleFrom, maleToFilter by male attendee count range
femaleFrom, femaleToFilter by female attendee count range
organizerFrom, organizerToFilter by organizer count range

Visibility and feed rules:

visible = event.visibility = 'public'

The feed excludes the viewer's own events, accepted author events, and friends' events, and excludes events that have already started. friendsOnly is accepted for compatibility but currently ignored. Without coordinates it returns the global feed, sorted by start time. With coordinates, radius is optional and distance is included in the result. Search supports q, single type, or comma-separated/repeated types.

Sort order: distance ASC when a point is supplied, then start_at ASC. See Feed algorithm for the full details and boost-by-preferences design.

Update / cancel / delete​

PATCH /events/:id # only while now() < startAt
POST /events/:id/cancel # any time, by creator or any author
DELETE /events/:id # soft delete (sets deleted_at)
POST /events/:id/restore # before status='finished'

After start_at the event becomes immutable for content fields. See Event lifecycle for the locked-fields list and state machine.

Authors​

Only friends of the creator can be invited as authors. Invitations have pending, accepted, and refused states. Only accepted co-authors count as organizers for quorum, voting, and the organizers' chat. Creating an event also creates its event_authors chat; this is separate from an approved group's chat.

POST /events/:id/authors
{ "userId": "friend-uuid" }
LimitValue
Authors per event10

Like an event​

Solo or group like.

POST /events/:id/like
{ "memberIds": ["friend-1", "friend-2"] } // optional
  • Without memberIds → solo like (group of size 1).
  • All memberIds must be friends of the caller.
  • A user can only be in one pending like group per event.
{
"id": "group-uuid",
"eventId": "event-uuid",
"status": "pending",
"memberIds": ["caller-uuid", "friend-1", "friend-2"]
}

See the Like Groups API for approval, removal and chat-creation side effects.

Implementation notes​

  • Geo: events store geography(Point, 4326). PostGIS is required; see api/docs/DATABASE.md for the existing setup of geography columns on cities and profiles.
  • Soft delete: deleted_at is partial-indexed for fast feed queries (WHERE deleted_at IS NULL).
  • Realtime: clients can subscribe to event:{eventId} via Supabase Realtime to receive event.updated notifications.
  • Module layout will follow the shipped pattern: src/feats/events/{router,service,schemas,constants}.ts.