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 endpoint-domain documentation linked below is authoritative for each route family. Live API availability can be confirmed at GET /api/v1/openapi. Some routes (notably Events and Culture families) remain partially or fully planned.

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

Live OpenAPI Spec ​

The Kubuli API serves a machine-readable OpenAPI 3.1.0 specification at GET /api/v1/openapi (no auth required). This endpoint reflects the actual route definitions, request/response schemas, and error codes for all shipped route families.

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
CommerceCart (/api/v1/cart), checkout with idempotency (POST /api/v1/checkout), customer orders (/api/v1/me/orders), merchant inventory (/api/v1/me/places/*), payment methods, payout details, and disbursements — liveKUB-207eCommerce and merchant MVP: cart, checkout, orders, storefront menu, place claims
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