Authenticated application endpoints are prefixed with /api/v1 and require a
valid Clerk JWT in the Authorization: Bearer <token> header unless noted
otherwise.
Successful single-resource responses return the resource directly:
Event-list endpoints return a list plus pagination metadata shaped as { data, pagination }:
"data" : [{ "id" : " evt_123 " , "title" : " Hack Night " }],
"pagination" : { "total" : 100 , "limit" : 20 , "offset" : 0 }
Recommendation endpoints return section items plus metadata shaped as { items, meta }:
"items" : [{ "id" : " evt_123 " , "title" : " Hack Night " }],
"rankingMode" : " PERSONALIZED "
Route-specific exceptions:
GET /api/v1/users/:id embeds createdEvents as { items, meta }
GET /api/v1/admin/ai-pipeline/jobs returns a bare array of jobs
Error responses use RFC 7807 Problem Details with the appropriate HTTP status
code:
"type" : " https://social-osu.app/problems/not-found " ,
"title" : " Resource not found " ,
"detail" : " Event evt_123 was not found "
Most paginated endpoints use limit (default 20, max 100) and offset
(default 0). Exceptions: GET /api/v1/events/semantic-search uses limit
default 10, max 25; GET /api/v1/admin/ai-pipeline/jobs uses limit default
10, max 25. All timestamps are UTC (ISO 8601).
Method Path Description GET /api/healthUnauthenticated API health check returning service, status, and timestamp
Method Path Description GET /api/v1/auth/meGet the authenticated request-context user (id, clerkId, email, role)
Method Path Description GET /api/v1/users/meGet authenticated user’s profile, including persisted role PATCH /api/v1/users/meUpdate profile fields (role, email, id, and clerkId remain immutable) GET /api/v1/users/me/applicationsList the authenticated user’s gig applications with gig summaries. Params: limit, offset GET /api/v1/users/:idGet public profile of a user. Params: limit, offset apply to createdEvents POST /api/v1/users/:id/followFollow another user. Returns 201 with an empty JSON object DELETE /api/v1/users/:id/followUnfollow a user. Returns 204 GET /api/v1/users/:id/followersList follower profiles for a user. Params: limit, offset GET /api/v1/users/:id/followingList profiles the user follows. Params: limit, offset
Method Path Description POST /api/v1/admin/external-ingestion/syncTrigger a synchronous external event sync. ADMIN only. Returns startedAt, finishedAt, and per-source counters GET /api/v1/admin/ai-pipeline/jobsList recent AI pipeline jobs. ADMIN only. Param: limit POST /api/v1/admin/ai-pipeline/events/:id/rerunQueue an AI pipeline rerun for an event. ADMIN only. Body: { mode?: "EMBEDDING" | "FULL_PIPELINE" } POST /api/v1/admin/ai-pipeline/backfillQueue an embedding backfill job. ADMIN only
Method Path Description GET /api/v1/social/feedGet events from followed users. Params: limit, offset
Method Path Description GET /api/v1/eventsList events. Filters: type, category, startDate, endDate, source, status, statusMode, user, search, sort, limit, offset GET /api/v1/events/semantic-searchSemantic event search. Filters: query, type, category, startDate, endDate, limit, offset. Returns the same { data, pagination } envelope as /api/v1/events POST /api/v1/eventsCreate an event or gig GET /api/v1/events/:idGet a single event with full detail PATCH /api/v1/events/:idUpdate event (owner only; forbidden for external events) DELETE /api/v1/events/:idDelete event (owner only; forbidden for external events). Returns 200 with { message: "Event deleted" }
:gigId is an Event ID. The system validates that the event has type = GIG. Returns 400 if the event is not a gig.
Method Path Description POST /api/v1/gigs/:gigId/applicationsApply to a gig. Body: { message? } GET /api/v1/gigs/:gigId/applicationsList applications (owner sees all; applicant sees only their own). Params: limit, offset PATCH /api/v1/gigs/:gigId/applications/:appIdUpdate application status (gig owner only). Body: { status }
Method Path Description GET /api/v1/collectionsList authenticated user’s collections, including item counts POST /api/v1/collectionsCreate a collection GET /api/v1/collections/:idGet collection with collection items and expanded event payloads (respects visibility) PATCH /api/v1/collections/:idUpdate collection (owner only) DELETE /api/v1/collections/:idDelete collection and items (owner only) POST /api/v1/collections/:id/itemsAdd event to collection. Body: { eventId } DELETE /api/v1/collections/:id/items/:eventIdRemove event from collection
Method Path Description POST /api/v1/interactionsRecord a user interaction
Method Path Description GET /api/v1/recommendationsGet the Recommended Featured feed section. Params: limit, offset, type, search. Response meta also includes rankingMode GET /api/v1/recommendations/popularGet the Popular Featured preview section. Params: limit, offset, type, search GET /api/v1/recommendations/upcomingGet the Upcoming Featured preview section. Params: limit, offset, type, search
Method Path Description POST /api/v1/conversations/:id/messagesSend a message to an existing conversation; returns streamed SSE response
HTTP Status Code When 400 BAD_REQUEST Invalid input, invalid query, invalid status transition, applying to a non-gig event, or applying to a non-open gig 401 UNAUTHORIZED Missing or invalid JWT 403 FORBIDDEN Ownership violation, self-application to own gig, unauthorized gig-application visibility, or non-admin access to admin endpoints 404 NOT_FOUND Resource not found or private resource accessed by a non-owner 409 CONFLICT Duplicate application or duplicate collection item 500 INTERNAL_ERROR Unexpected server error