Skip to content

API Overview

The Kubuli API is a HonoX application running on Node.js locally and currently built as a Node SSR bundle. All versioned endpoints are under the /api/v1 prefix.

Current status

The implemented API surface includes GET /, GET /health, GET /api/health, GET /api/v1/app/*, GET /api/v1/feed, GET /api/v1/feed/dashboard, GET /api/v1/categories, GET /api/v1/places, GET /api/v1/places/dashboard, GET /api/v1/places/:id, GET /api/v1/search, GET /api/v1/map/pois, GET /api/v1/events/dashboard, GET|POST|DELETE /api/v1/favorites*, POST|GET /api/v1/tours*, GET /api/v1/tours/dashboard, POST|GET /api/v1/tours/:tourId/stops/:stopId/reviews, POST /api/v1/reviews/:reviewId/votes, POST /api/v1/reviews/:reviewId/flag, POST /api/v1/auth/register, POST /api/v1/auth/login, POST /api/v1/auth/guest, POST /api/v1/auth/refresh, POST /api/v1/auth/phone/send-otp, POST /api/v1/auth/phone/verify-otp, POST /api/v1/auth/phone/resend-otp, GET /api/v1/me, PATCH /api/v1/me, GET /api/v1/me/preferences, GET /api/v1/users/handle/check, POST /api/v1/users/profile, and the Better Auth handler mounted at /api/auth/*.

The sections below mix live and planned route families. Events, Culture, and the map summary/distance routes remain planned unless otherwise noted.

Base URLs

EnvironmentBase URL
Localhttp://localhost:3001
Staginghttps://api.kubuli.platform.mhdevnet.net
ProductionTBD

Authentication

Pass a valid JWT in the Authorization header:

http
Authorization: Bearer <token>

→ See Registration and Authentication for auth flows.

Endpoint Domains

DomainCurrent Paths / StatusJiraDescription
App / Onboarding/api/v1/app/*, /api/v1/me/preferences — liveKUB-120–123Home config, tour slides, intro video, user preferences
FeedGET /api/v1/feed, GET /api/v1/feed/dashboard — liveKUB-174Global mixed-content feed plus aggregate dashboard sections with differentiated rate limits
Categories/api/v1/categories — liveKUB-124Visual discovery category grid
Places/api/v1/favorites*, GET /api/v1/places, GET /api/v1/places/dashboard, GET /api/v1/places/:id, GET /api/v1/places/:id/photos, and GET /api/v1/search — liveKUB-125–130, KUB-151POI / venue browse, dashboard, detail, photos, search, favorites
EventsGET /api/v1/events/dashboard — live; /api/v1/events* list/detail/poll and /api/v1/areas — plannedKUB-131–137Real-time feed, filters, areas listing
Culture/api/v1/culture/* — plannedKUB-138, 140, 143–144Stories, topics, TTS audio, OG meta
MapGET /api/v1/map/pois — live; GET /api/v1/map/pois/:id/summary and GET /api/v1/map/pois/:id/distance — plannedKUB-139, 141–142, 145Viewport POIs, POI summary, distance
MediaPOST /api/v1/places/:id/photos, POST /api/v1/admin/places/:placeId/photos, PATCH /api/v1/admin/photos/:photoId, and DELETE /api/v1/admin/photos/:photoId — liveKUB-146, 149–151Community & curator photo upload/management
Tours/api/v1/tours*, GET /api/v1/tours/dashboard — liveKUB-181, KUB-182, KUB-184, KUB-186–188Personalized tours, dashboard, preview, directions, completion, video
Reviews/api/v1/tours/:tourId/stops/:stopId/reviews, /api/v1/reviews/:reviewId/votes, /api/v1/reviews/:reviewId/flag — liveKUB-185In-app reviews, aggregates, votes, flags, external badges
Registration/api/v1/auth/register, GET /api/v1/users/handle/check, POST /api/v1/users/profile — liveKUB-112 (registration), KUB-114–115Email account creation and post-registration onboarding
Authentication/api/v1/auth/login, /api/v1/auth/guest, /api/v1/auth/refresh, /api/v1/auth/phone/*, /api/v1/me, /api/auth/* — live; logout and deletion remain plannedKUB-111, KUB-112 (login), KUB-113, KUB-116–118, KUB-148Email, social, guest, session, token, and deletion flows

Current-user endpoints use the /api/v1/me namespace for profile and preference surfaces (for example, GET /api/v1/me, PATCH /api/v1/me, and GET /api/v1/me/preferences).

/api/v1/map/pois* is a map-optimized projection for viewport and callout performance. Canonical place detail and gallery data remains under /api/v1/places*, and IDs are shared across both surfaces.

Current Live Response Format

The shipped auth endpoints under /api/v1/auth/* and /api/v1/me return a consistent envelope:

json
{
	"data": { ... }
}

Most live endpoints now use the same top-level data envelope. GET /api/v1/places uses page-based pagination via meta.page, meta.limit, meta.total, and meta.total_pages. Cursor-based pagination is already live on several other list routes, including tours and tour-stop reviews, via meta.cursor. GET /api/v1/map/pois returns a bounded data array with no pagination metadata.

Planned List Response Format

json
{
  "data": [...],
  "meta": { "next_cursor": "eyJpZCI6MTIzfQ==", "total": 156 }
}

Pass ?limit=N&cursor={token} to paginate cursor-based route families once they ship. Request a minimal payload with ?format=minimal or sparse fieldsets with ?fields=id,name,lat,lng once the endpoint family is implemented. The live GET /api/v1/places and GET /api/v1/map/pois routes are existing exceptions to that planned cursor contract.

Current Error Formats

Routes that use the shared API error helpers (for example most shipped auth routes plus the newer tours and reviews handlers) return a machine-readable envelope:

json
{
	"error": {
		"code": "not_found",
		"message": "Not found",
		"status": 404
	}
}
HTTP statusCurrent helper-backed code values
400invalid_body
401auth_required, invalid_credentials
409email_taken
422validation_error
429rate_limited

The API-level fallback handlers for unmatched routes and unhandled exceptions still return a flatter legacy shape today:

json
{
	"error": "Not Found",
	"status": 404
}
json
{
	"error": "Internal Server Error",
	"status": 500
}

Treat the structured error.code envelope as the current contract for helper-backed route families, not as a blanket guarantee for every API failure path yet.

Rate Limiting

The shipped API currently enforces in-memory rate limiting on selected route families:

Route familyLimit
POST /api/v1/auth/login10 requests / minute per resolved client key
POST /api/v1/auth/register10 requests / minute per resolved client key
GET /api/v1/feed30 requests / minute for unauthenticated callers; 120 requests / minute for authenticated users
POST /api/v1/tours, POST /api/v1/tours/generate5 requests / hour per authenticated user
POST /api/v1/reviews/:reviewId/votes120 write actions / minute per authenticated user

Broader default API-wide rate limiting remains planned.

Built with VitePress