Skip to main content

Events API

Planned

This module is not yet shipped. The shape below describes the intended endpoints on the new Hono + Supabase + Drizzle stack. Geo queries depend on enabling PostGIS on the Supabase Postgres (already documented in api/docs/DATABASE.md).

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

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
descriptionstring
typeenumparty, dinner, outdoor, sports
visibilityenumpublic, private
startAtISO8601
endAtISO8601
latitudenumberWGS84
longitudenumberWGS84
capacityintDefault 200; creator + authors don't count

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 (default 5000) — uses ST_DWithin on geography(Point, 4326)
typeFilter by event type
friendsOnlyOnly events created by friends
cursor, limitPagination
startDate, endDateISO date range filter

Visibility rule:

visible = event.visibility = 'public' OR is_friend(viewer, event.creator)

Sort order: distance ASC, 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.

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.