API Reference
The deployed API serves all endpoints below at https://code-sensei-search-api.vercel.app/api. Swagger UI with live schemas is at /api/docs.
Conventions
No auth on search
The search, suggestions, and stats endpoints are public. Authentication is only required for admin and ingestion trigger routes (not documented here).
Rate limit
Global limit is 60 requests per minute per IP, enforced by NestJS Throttler. Requests that exceed the window get 429 with the standard rate-limit headers.
Response envelope
Successful responses wrap the payload in { success: true, data: ... }. Errors follow NestJS's standard { statusCode, message } shape.
CORS
Allowed origin is set via the FRONTEND_URL env var on the API. For local development, add your origin to the same var and redeploy, or run the API locally.
Endpoints
/api/healthLiveness + dependency reachability probe. Reports DB, Redis, and Gemini status independently. 200 when DB + Redis are up; 503 otherwise.
Request
curl https://code-sensei-search-api.vercel.app/api/healthResponse
{
"status": "ok",
"timestamp": "2026-04-23T...",
"service": "CodeSenseiSearch API",
"version": "0.1.0",
"uptimeSec": 42,
"components": {
"database": { "status": "up", "latencyMs": 21 },
"redis": { "status": "up", "latencyMs": 2 },
"gemini": { "status": "up" }
}
}/api/search/hybridRecommended default. Runs vector + full-text search in parallel, merges them with a configurable weighted score (default 0.6 vector / 0.4 text), and reranks the top K.
Request
curl -X POST https://code-sensei-search-api.vercel.app/api/search/hybrid \
-H "content-type: application/json" \
-d '{
"query": "useEffect cleanup",
"options": {
"limit": 10,
"vectorWeight": 0.6,
"textWeight": 0.4
}
}'Response
{
"success": true,
"data": {
"query": "useEffect cleanup",
"results": [
{
"id": "ckn...",
"chunkText": "A useEffect cleanup runs on two occasions...",
"similarity": 0.87,
"source": "documentation",
"language": "javascript",
"title": "How do React useEffect cleanup functions work?"
}
],
"totalResults": 10,
"searchTime": 112,
"searchMethod": "hybrid",
"metadata": {
"embeddingGenerated": true,
"vectorSearchUsed": true,
"textSearchUsed": true,
"vectorResults": 12,
"textResults": 8,
"mergedResults": 10
}
}
}/api/search/semanticVector-only search. Embeds the query with Gemini RETRIEVAL_QUERY and returns top-K by cosine similarity against stored chunk embeddings.
Request
curl -X POST https://code-sensei-search-api.vercel.app/api/search/semantic \
-H "content-type: application/json" \
-d '{"query": "distributed lock with Redis", "options": {"limit": 5}}'Response
{
"success": true,
"data": {
"query": "distributed lock with Redis",
"results": [ /* similar shape to hybrid, but no text-search metadata */ ],
"totalResults": 5,
"searchMethod": "semantic"
}
}/api/search/textFull-text search via Postgres tsvector + ts_rank. Useful when you already know the keywords and want lexical precision.
Request
curl -X POST https://code-sensei-search-api.vercel.app/api/search/text \
-H "content-type: application/json" \
-d '{"query": "pgvector HNSW", "options": {"limit": 5}}'Response
{
"success": true,
"data": {
"query": "pgvector HNSW",
"results": [ /* ... */ ],
"totalResults": 3,
"searchMethod": "text"
}
}/api/search/suggestionsAutocomplete hints for the search bar. Returns an array of suggested completions based on the prefix. Pass at least 2 chars.
Request
curl "https://code-sensei-search-api.vercel.app/api/search/suggestions?q=react"Response
{
"success": true,
"data": {
"query": "react",
"suggestions": ["react useEffect", "react server components"]
}
}/api/search/statsCorpus-wide counts. Chunks, chunks-with-embeddings, per-content-type split, and the list of languages present in the index.
Request
curl https://code-sensei-search-api.vercel.app/api/search/statsResponse
{
"success": true,
"data": {
"totalChunks": 15,
"chunksWithEmbeddings": 15,
"embeddingCoverage": 1.0,
"repositoryChunks": 0,
"questionChunks": 0,
"availableLanguages": ["javascript", "typescript", "python", "go", "rust"]
}
}Status codes
| Code | Name | When |
|---|---|---|
| 400 | Bad Request | Missing `query` or invalid options |
| 403 | Forbidden | Only applies to guarded operator routes (/api/seed, /api/admin) |
| 429 | Too Many Requests | Global rate limit of 60 requests per minute per IP is in effect on all routes |
| 500 | Internal Error | Unexpected server fault; check /api/health |
| 503 | Service Unavailable | Returned by /api/health when either the DB or Redis is down; transient, worth retrying |