API Reference
Complete endpoint documentation for all Sentinel services
API Reference
Complete endpoint documentation for all Sentinel services. All API calls route through the Studio Backend (BFF) at studio-backend-dev.centricitywealth.tech. The frontend never calls downstream microservices directly.
Response Envelope
All V1 endpoints return a standard ResponseEnvelope<T>:
{
"success": true,
"message": "Operation completed",
"error": null,
"result": { /* T — the actual payload */ }
}
The api-client.ts layer automatically unwraps this envelope so callers receive T directly. V2 pipeline progress is the exception – it returns raw JSON without an envelope.
graph LR
Raw["API Response<br/>{success, result: T}"]:::primary --> Client["api-client.ts<br/>Unwraps envelope"]:::secondary
Client --> Caller["Caller gets T<br/>directly"]:::success
V2["V2 Progress<br/>Raw JSON"]:::neutral --> Smart["Smart detection<br/>Pass through as-is"]:::warning
Smart --> Caller
classDef primary fill:#dbeafe,stroke:#3b82f6,color:#1e293b
classDef secondary fill:#e0e7ff,stroke:#6366f1,color:#1e293b
classDef success fill:#d1fae5,stroke:#10b981,color:#1e293b
classDef warning fill:#fef3c7,stroke:#f59e0b,color:#1e293b
classDef danger fill:#fee2e2,stroke:#ef4444,color:#1e293b
classDef neutral fill:#f1f5f9,stroke:#64748b,color:#1e293b
classDef highlight fill:#fae8ff,stroke:#a855f7,color:#1e293b
classDef dark fill:#1e293b,stroke:#334155,color:#f8fafc
Request Lifecycle
Every API call flows through a consistent chain: React Query hook, API module, gateway layer, and the shared api-client.ts. The following diagram traces a complete request from the page component down to the Studio BFF and back.
sequenceDiagram
participant Page as Page Component
participant Hook as React Query Hook
participant API as API Module
participant GW as Gateway
participant Client as api-client.ts
participant BFF as Studio BFF
Page->>Hook: useQuery / useMutation
Hook->>API: nexus.getDocuments()
API->>GW: nexusRequest('/documents/')
GW->>Client: request('/nexus/documents/')
Client->>Client: Build URL + Add Bearer
Client->>BFF: GET /api/v1/nexus/documents/
BFF-->>Client: ResponseEnvelope
Client-->>Client: Unwrap .result
Client-->>GW: T
GW-->>API: T
API-->>Hook: T
Hook-->>Page: { data: T }
Auth (Server Actions)
Authentication is handled server-side via Next.js Server Actions. Tokens are stored in encrypted HttpOnly cookies and are never exposed to the browser.
| Method | Endpoint | Description |
|---|---|---|
| POST | /api/v1/auth/login |
Login with email and password |
| POST | /api/v1/auth/register |
Create a new account |
| POST | /api/v1/auth/refresh |
Refresh the access token |
| POST | /api/v1/auth/logout |
Logout and clear the session |
POST /api/v1/auth/login
Request:
{
"email": "user@example.com",
"password": "your-password"
}
Response:
{
"success": true,
"message": "Login successful",
"result": {
"access_token": "eyJhbG...",
"refresh_token": "eyJhbG...",
"user": {
"id": "uuid",
"email": "user@example.com",
"full_name": "John Doe",
"role": "user"
}
}
}
POST /api/v1/auth/register
Request:
{
"email": "user@example.com",
"password": "secure-password",
"full_name": "John Doe"
}
POST /api/v1/auth/refresh
Headers:
Authorization: Bearer <refresh_token>
Response: Returns a new access_token and refresh_token pair.
Dashboard
Aggregated platform metrics and activity feed for the authenticated user.
| Method | Endpoint | Description |
|---|---|---|
| GET | /api/v1/dashboard?period=all_time |
Aggregated platform metrics |
| GET | /api/v1/dashboard/activity?page=1&limit=20 |
Activity feed with pagination |
GET /api/v1/dashboard?period=all_time
Returns high-level stats: documents processed, extraction count, success rate, AI conversation count, and token usage.
Query Parameters:
period— One ofall_time,7d,30d,90d
Response (unwrapped):
{
"documents_processed": 142,
"extractions": 138,
"success_rate": 97.2,
"conversations": 56,
"token_usage": {
"total_tokens": 1250000,
"total_cost_inr": 4200.50
}
}
GET /api/v1/dashboard/activity?page=1&limit=20
Returns a paginated list of recent activity events (uploads, extractions, chats).
Nexus (V1)
Document intelligence endpoints for upload, extraction, export, and metadata.
| Method | Endpoint | Description |
|---|---|---|
| GET | /api/v1/documents/me?limit=50&skip=0 |
List authenticated user’s documents with pagination |
| GET | /api/v1/nexus/documents/{doc_id}/extraction |
Get extraction data for a document |
| POST | /api/v1/nexus/upload/ |
Upload a document (multipart/form-data) |
| GET | /api/v1/nexus/doc-fetch/{job_id}?type=ORIGINAL |
Fetch the original uploaded PDF |
| GET | /api/v1/nexus/export/{job_id}/fields |
Get export field definitions |
| GET | /api/v1/nexus/token-usage/{doc_id} |
Token usage breakdown by stage |
| GET | /api/v1/nexus/stats |
Platform-wide stats (admin-only) |
GET /api/v1/documents/me?limit=50&skip=0
Returns only the authenticated user’s documents. Replaced the previous admin-scoped /nexus/documents/ endpoint as of v6.2.
Query Parameters:
limit— Number of documents to return (default: 50)skip— Offset for pagination (default: 0)
Response (unwrapped):
[
{
"doc_id": "uuid",
"job_id": "uuid",
"file_name": "CAS_Statement_Jan2026.pdf",
"status": "completed",
"classification": "CAS",
"confidence_score": 95.4,
"created_at": "2026-02-18T10:30:00Z",
"updated_at": "2026-02-18T10:35:00Z"
}
]
GET /api/v1/nexus/documents/{doc_id}/extraction
Returns the full extraction result including securities holdings, asset allocation, and account metadata.
Response (unwrapped):
{
"doc_id": "uuid",
"entities": [
{
"entity_name": "John Doe",
"pan": "ABCDE1234F",
"holdings": [
{
"scheme_name": "HDFC Top 100 Fund",
"isin": "INF179K01AB3",
"units": 150.25,
"nav": 845.32,
"market_value": 127007.34,
"asset_class": "Equity"
}
],
"asset_allocation": {
"equity": 65.2,
"debt": 25.8,
"hybrid": 9.0
}
}
]
}
POST /api/v1/nexus/upload/
Upload a financial document for processing.
Request: multipart/form-data
file— The PDF file to upload
Response (unwrapped):
{
"job_id": "uuid",
"doc_id": "uuid",
"status": "uploaded",
"password_required": false,
"password_hint": null
}
GET /api/v1/nexus/doc-fetch/{job_id}?type=ORIGINAL
Fetches the original uploaded PDF binary. Returns the file as application/pdf.
Query Parameters:
type—ORIGINALfor the uploaded PDF,LAYOUTfor layout analysis images
GET /api/v1/nexus/export/{job_id}/fields
Returns available export field definitions for a processed document.
Query Parameters (optional):
export_type—holdingsorunderlying
GET /api/v1/nexus/token-usage/{doc_id}
Returns per-stage token usage with cost breakdown.
Response (unwrapped):
{
"doc_id": "uuid",
"stages": [
{
"stage_name": "classification",
"model": "gpt-4o",
"input_tokens": 1200,
"output_tokens": 450,
"cost_inr": 12.50
}
],
"total_tokens": 45000,
"total_cost_inr": 185.00
}
GET /api/v1/nexus/stats
Access: Admin-only. Returns platform-wide statistics across all users.
Nexus (V2 Pipeline)
Version 2 endpoints for the document processing pipeline. V2 introduces process_id-based tracking alongside job_id.
| Method | Endpoint | Description |
|---|---|---|
| POST | /api/v2/nexus/pipeline/process |
Start the document processing pipeline |
| GET | /api/v2/nexus/status/process/{process_id}/progress |
Poll pipeline progress |
POST /api/v2/nexus/pipeline/process
Initiates the 10-stage AI extraction pipeline for an uploaded document.
Request:
{
"job_id": "uuid"
}
Response (unwrapped):
{
"process_id": "uuid",
"job_id": "uuid",
"status": "processing"
}
Note: The
process_idis stored in the frontend’snexus-store.processIdMapand used for all subsequent progress polling.
GET /api/v2/nexus/status/process/{process_id}/progress
Polls the current progress of a running pipeline.
Important: This endpoint returns raw JSON without a ResponseEnvelope. The
api-client.tssmart detection passes it through as-is.
Response (raw, no envelope):
{
"process_id": "uuid",
"status": "processing",
"progress_pct": 60,
"current_stage": "extraction",
"stages_completed": 6,
"total_stages": 10,
"stages": [
{
"name": "classification",
"status": "completed",
"duration_ms": 2300
},
{
"name": "extraction",
"status": "in_progress",
"duration_ms": null
}
]
}
Pipeline Stages (in order):
| # | Stage | Description |
|---|---|---|
| 1 | Upload | File received and validated |
| 2 | Classification | Document type identification |
| 3 | Parsing | Text extraction from PDF |
| 4 | Structuring | Content structure analysis |
| 5 | Extraction | Securities and holdings extraction |
| 6 | Validation | Data integrity checks |
| 7 | Enrichment | Market data enrichment |
| 8 | Calculation | Portfolio calculations |
| 9 | Summary | AI-generated document summary |
| 10 | Completion | Final output assembly |
Polling Flow
After the frontend starts a V2 pipeline, it polls the progress endpoint every 2 seconds until progress_pct reaches 100. The progress endpoint returns raw JSON (no ResponseEnvelope), which api-client.ts detects and passes through as-is.
sequenceDiagram
participant FE as Frontend
participant BFF as Studio BFF
participant Nexus as Nexus Backend
FE->>BFF: POST /v2/pipeline/process
BFF->>Nexus: Start pipeline
Nexus-->>BFF: { process_id, job_id }
BFF-->>FE: { process_id, job_id }
loop Every 2 seconds
FE->>BFF: GET /v2/status/process/{id}/progress
BFF->>Nexus: Check progress
Nexus-->>BFF: { progress_pct, stages_completed }
BFF-->>FE: Raw JSON (no envelope)
end
Note over FE: progress_pct reaches 100
FE->>BFF: GET /v1/nexus/documents/{id}/extraction
BFF-->>FE: Extraction data
Zen
Financial AI chat endpoints. Zen uses a synchronous (non-streaming) request/response model. Messages are sent as FormData, not JSON.
| Method | Endpoint | Description |
|---|---|---|
| POST | /api/v1/zen/chat/ |
Create a new chat session (returns bare UUID) |
| POST | /api/v1/zen/chat/invoke |
Send a message (FormData, synchronous) |
| GET | /api/v1/zen/chat/sessions/summary |
List all sessions with summaries |
| GET | /api/v1/zen/chat/session/{session_id} |
Get a session with its full message history |
| PUT | /api/v1/zen/chat/session/{session_id} |
Rename a session |
| DELETE | /api/v1/zen/chat/session/{session_id} |
Delete a session |
| POST | /api/v1/zen/uploads/ |
Upload a file for RAG-powered chat |
| GET | /api/v1/zen/chat/{session_id}/documents/{doc_id}/status |
Poll Nexus processing status for a document in a session |
POST /api/v1/zen/chat/
Creates a new chat session.
Response: Returns a bare UUID string (not wrapped in an object).
"a1b2c3d4-e5f6-7890-abcd-ef1234567890"
POST /api/v1/zen/chat/invoke
Sends a message and receives the AI response synchronously.
Request: multipart/form-data
| Field | Type | Required | Description |
|---|---|---|---|
session_id |
string | Yes | UUID of the chat session |
query |
string | Yes | The user’s message text |
skip_guardrail |
string | No | "true" or "false" (default: "false") |
web_search |
string | No | "true" or "false" — enable real-time web search |
agent_id |
string | No | MongoDB ObjectId of a specific agent to invoke |
Response (unwrapped):
{
"status": "success",
"message_id": "uuid-of-user-message",
"response_message_id": "uuid-of-ai-response",
"response": "Based on current data, the top performing large-cap mutual funds are...",
"meta": {
"web_search": "True",
"agents_invoked": [
{
"agent_id": "6989c8987e0f5c816015fd18",
"agent_name": "Market Research"
}
]
},
"guardrail": null,
"error": null
}
Key detail: AI messages must be keyed by
response_message_id, notmessage_id. Themessage_idfield refers to the user’s message. Themeta.web_searchfield is a string ("True"/"False"), not a boolean.
GET /api/v1/zen/chat/sessions/summary
Returns all chat sessions for the authenticated user, ordered by most recent.
Response (unwrapped):
[
{
"session_id": "uuid",
"title": "Portfolio Analysis Discussion",
"created_at": "2026-02-18T14:20:00Z",
"updated_at": "2026-02-18T15:45:00Z",
"message_count": 12
}
]
GET /api/v1/zen/chat/session/{session_id}
Returns a single session with its complete message history.
PUT /api/v1/zen/chat/session/{session_id}
Request:
{
"title": "New Session Title"
}
DELETE /api/v1/zen/chat/session/{session_id}
Permanently deletes a chat session and all its messages.
POST /api/v1/zen/uploads/
Uploads a file for RAG-powered document Q&A within a chat session.
Request: multipart/form-data
| Field | Type | Required | Description |
|---|---|---|---|
file |
File | Yes | The document to upload (PDF) |
session_id |
string | Yes | UUID of the chat session |
Response (unwrapped):
{
"document_ids": ["uuid"],
"file_name": "quarterly_report.pdf",
"status": "processed"
}
GET /api/v1/zen/chat/{session_id}/documents/{doc_id}/status
Polls the processing status of a document attached to a chat session. Used by the NexusProcessingIndicator component to show live Nexus pipeline progress within the chat UI. Called with suppressAuthEvent: true so 401 responses from background polling do not trigger the global session-expired modal.
Response (unwrapped):
{
"doc_id": "uuid",
"status": "nexus_processing",
"filename": "CAS_Jan2026.pdf",
"source": "nexus",
"chunks_indexed": 0,
"nexus_progress": {
"current_stage": "entity_detect",
"stages_completed": 4,
"total_stages": 10,
"status": "processing",
"progress_pct": 40
},
"error_message": null
}
Status values:
| Status | Meaning |
|---|---|
processing |
Document being ingested for RAG |
nexus_processing |
Document running through the Nexus 10-stage pipeline |
completed |
Fully indexed and ready for queries |
failed |
Pipeline or ingestion error |
Health Checks
| Method | Endpoint | Description |
|---|---|---|
| GET | /api/v1/health/ |
Studio Backend health |
| GET | /api/v1/discovery/services/nexus/health |
Nexus service health via discovery |
Authentication
All endpoints (except auth and health) require a Bearer token in the Authorization header:
Authorization: Bearer <access_token>
The frontend reads the access token from the in-memory Zustand auth store. The token is never persisted to localStorage – only the user profile is persisted. Token refresh is handled automatically via encrypted HttpOnly cookies on the server side.
Error Handling
Failed requests return the standard envelope with success: false:
{
"success": false,
"message": "Document not found",
"error": {
"code": "NOT_FOUND",
"details": "No document with ID abc-123"
},
"result": null
}
Common HTTP status codes:
| Status | Meaning |
|---|---|
| 200 | Success |
| 400 | Bad request (validation error) |
| 401 | Unauthorized (token expired or missing) |
| 403 | Forbidden (insufficient permissions) |
| 404 | Resource not found |
| 413 | Payload too large (file upload) |
| 500 | Internal server error |
BFF Routing Summary
All 32 Nexus routes are explicitly defined in the Studio Backend middleware. Zen routes use a wildcard proxy pattern. The frontend’s gateway layers (nexus-gateway.ts, zen-gateway.ts) prepend the service prefix (/nexus, /zen) to all paths before the api-client.ts constructs the final URL as {baseUrl}/api/{version}/{path}.
| Gateway | Prefix | Routing |
|---|---|---|
| Nexus | /nexus |
32 explicit middleware routes |
| Zen | /zen |
Wildcard proxy |
URL Construction: api-client.ts defaults to V1. Use apiVersion: 'v2' to override for pipeline endpoints.
Last Updated: March 3, 2026