Skip to content

API Endpoints

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:

{
"id": "user_123",
"displayName": "Carmen"
}

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" }],
"meta": {
"total": 100,
"limit": 20,
"offset": 0,
"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",
"status": 404,
"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).

MethodPathDescription
GET/api/healthUnauthenticated API health check returning service, status, and timestamp
MethodPathDescription
GET/api/v1/auth/meGet the authenticated request-context user (id, clerkId, email, role)
MethodPathDescription
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
MethodPathDescription
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
MethodPathDescription
GET/api/v1/social/feedGet events from followed users. Params: limit, offset
MethodPathDescription
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.

MethodPathDescription
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 }
MethodPathDescription
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
MethodPathDescription
POST/api/v1/interactionsRecord a user interaction
MethodPathDescription
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
MethodPathDescription
POST/api/v1/conversations/:id/messagesSend a message to an existing conversation; returns streamed SSE response
HTTP StatusCodeWhen
400BAD_REQUESTInvalid input, invalid query, invalid status transition, applying to a non-gig event, or applying to a non-open gig
401UNAUTHORIZEDMissing or invalid JWT
403FORBIDDENOwnership violation, self-application to own gig, unauthorized gig-application visibility, or non-admin access to admin endpoints
404NOT_FOUNDResource not found or private resource accessed by a non-owner
409CONFLICTDuplicate application or duplicate collection item
500INTERNAL_ERRORUnexpected server error