HTTP API

Base Surface

The current backend exposes FastAPI routers under:

  • /api/aibs/auth

  • /api/aibs/admin/users

  • /api/aibs/workspaces

  • /api/aibs/conversations

  • /api/aibs/documents

  • /api/aibs/chat

The app is served by FastAPI and publishes OpenAPI docs at /docs.

Identity Boundary

The API uses an AIBS auth boundary at the interface layer.

  • POST /api/aibs/auth/login validates credentials through the configured OpenSearch identity store.

  • Successful login requires the aibs-access role and sets an HTTP-only session cookie.

  • Workspace, document, conversation, and chat routes resolve their UserContext from that cookie session.

  • Workspace-local authorization is role based:

    • owner: full control, including workspace delete

    • admin: manage workspace state, non-owner members, and documents

    • member: upload/process documents and ask questions

    • viewer: read workspace state and ask questions

  • The legacy X-AIBS-User-Id header is accepted only when AIBS_AUTH_DEV_MODE=true.

  • Phase 1 sessions use a fixed TTL and process-local memory; single-worker API deployment is required until a persistent session store lands.

  • AIBS product-user administration is guarded by both aibs-access and aibs-admin.

  • Workspace membership is separate from product administration. AIBS admins do not automatically see every workspace.

Endpoints

POST /api/aibs/auth/login

Purpose:

  • validate credentials against the configured OpenSearch cluster and create a cookie-backed AIBS session

Request:

  • JSON body:

    • username (required)

    • password (required)

Success:

  • 200 OK

  • sets an HTTP-only session cookie

  • returns { "success": true, "data": { "expires_at", "user": { "user_id", "provider", "subject", "username", "roles", "apps", "email", "display_name" } } }

POST /api/aibs/auth/logout

Purpose:

  • revoke the current cookie session

Behavior:

  • reads the configured session cookie

  • clears the cookie even when the session is missing or already expired

Success:

  • 200 OK

  • returns { "success": true, "data": {} }

GET /api/aibs/auth/session

Purpose:

  • return the user profile attached to the current cookie session

Behavior:

  • requires a valid session cookie

Success:

  • 200 OK

  • returns the same session payload as login

GET /api/aibs/admin/users

Purpose:

  • list product users from the configured AIBS user directory

Query parameters:

  • q (optional username/search text)

  • limit (default 50, min 1, max 500)

  • include_non_aibs (default false; when true, include directory users that do not currently have aibs-access)

Behavior:

  • requires a principal with both aibs-access and aibs-admin

Success:

  • 200 OK

  • returns { "users": [UserDirectoryRecordResponse] }

GET /api/aibs/admin/users/{username}

Purpose:

  • fetch one user from the configured user directory

Behavior:

  • requires a principal with both aibs-access and aibs-admin

  • returns 404 when the user is not found

Success:

  • 200 OK

  • returns UserDirectoryRecordResponse

POST /api/aibs/admin/users

Purpose:

  • create an AIBS product user in the backing directory

Request:

  • JSON body:

    • username (required)

    • password (required)

    • display_name (optional)

    • email (optional)

    • aibs_admin (optional, default false)

Behavior:

  • requires a principal with both aibs-access and aibs-admin

  • created users always receive aibs-access

  • created admin users also receive aibs-admin

Success:

  • 201 Created

  • returns UserDirectoryRecordResponse

PUT /api/aibs/admin/users/{username}/entitlements

Purpose:

  • grant or revoke AIBS product roles for an existing directory user

Request:

  • JSON body:

    • access (required boolean)

    • admin (required boolean)

Behavior:

  • requires a principal with both aibs-access and aibs-admin

  • preserves non-AIBS directory roles

  • refuses to remove or disable the last enabled AIBS admin

Success:

  • 200 OK

  • returns UserDirectoryRecordResponse

PUT /api/aibs/admin/users/{username}/password

Purpose:

  • reset a directory user’s password

Request:

  • JSON body:

    • new_password (required)

Behavior:

  • requires a principal with both aibs-access and aibs-admin

Success:

  • 204 No Content

PUT /api/aibs/admin/users/{username}/disable

Purpose:

  • disable a directory user when supported by the backing provider

Behavior:

  • requires a principal with both aibs-access and aibs-admin

  • refuses to disable the last enabled AIBS admin

Success:

  • 204 No Content

POST /api/aibs/workspaces

Purpose:

  • create a new backend-owned workspace

Request:

  • JSON body:

    • name (required)

    • visibility (optional, defaults to private)

Success:

  • 201 Created

  • returns WorkspaceResponse

GET /api/aibs/workspaces

Purpose:

  • list workspaces visible to the current identity

Query parameters:

  • limit (default 50, min 1, max 200)

  • offset (default 0)

Success:

  • 200 OK

  • returns WorkspaceListResponse

GET /api/aibs/workspaces/{workspace_id}

Purpose:

  • fetch one workspace the current identity belongs to

Success:

  • 200 OK

  • returns WorkspaceResponse

PUT /api/aibs/workspaces/{workspace_id}

Purpose:

  • rename a workspace through the backend-owned workspace service

Behavior:

  • requires workspace owner or admin

  • rejects rename while workspace delete is already in progress

  • applies the aggregate rename rule and persists the updated workspace

Success:

  • 200 OK

  • returns WorkspaceResponse

GET /api/aibs/workspaces/{workspace_id}/members

Purpose:

  • list the members and roles for one workspace

Behavior:

  • requires any workspace role

  • rejects reads while workspace delete is already in progress

Success:

  • 200 OK

  • returns list[WorkspaceMemberResponse]

POST /api/aibs/workspaces/{workspace_id}/members

Purpose:

  • add a user to a workspace with a workspace-local role

Request:

  • JSON body:

    • username (preferred)

    • user_id (deprecated compatibility field)

    • role (required: owner, admin, member, or viewer)

Behavior:

  • requires workspace owner or admin

  • at least one of username or user_id is required

  • username-based adds resolve through the AIBS user directory

  • unknown usernames are rejected

  • if both username and user_id are supplied, they must resolve to the same user

  • adding an owner requires the requester to be an owner

  • rejects duplicate membership through the workspace aggregate

  • rejects changes while workspace delete is already in progress

Success:

  • 201 Created

  • returns WorkspaceMemberResponse

PUT /api/aibs/workspaces/{workspace_id}/members/{user_id}

Purpose:

  • change an existing workspace member role

Request:

  • JSON body:

    • role (required: owner, admin, member, or viewer)

Behavior:

  • requires workspace owner or admin

  • promoting to owner or demoting an owner requires the requester to be an owner

  • preserves the aggregate invariant that a workspace must keep at least one owner

  • rejects changes while workspace delete is already in progress

Success:

  • 200 OK

  • returns WorkspaceMemberResponse

DELETE /api/aibs/workspaces/{workspace_id}/members/{user_id}

Purpose:

  • remove a user from a workspace

Behavior:

  • requires workspace owner or admin

  • removing an owner requires the requester to be an owner

  • preserves the aggregate invariant that a workspace must keep at least one owner

  • rejects changes while workspace delete is already in progress

Success:

  • 204 No Content

POST /api/aibs/workspaces/{workspace_id}/archive

Purpose:

  • archive a workspace through the governance layer

Behavior:

  • requires workspace owner or admin

  • performs the domain archive transition

  • persists the archived workspace state

Success:

  • 200 OK

  • returns WorkspaceResponse

DELETE /api/aibs/workspaces/{workspace_id}

Purpose:

  • destructively delete a workspace and its bounded resources

Behavior:

  • requires workspace ownership

  • closes the in-process workspace boundary before destructive cleanup starts

  • rejects deletion if any bounded document is currently processing

  • deletes bounded documents first

  • deletes conversations next

  • removes the workspace record last

Success:

  • 204 No Content

POST /api/aibs/workspaces/{workspace_id}/conversations

Purpose:

  • create a lightweight persisted conversation bound to one workspace

Request:

  • JSON body:

    • title (optional)

Success:

  • 201 Created

  • returns ConversationResponse

GET /api/aibs/workspaces/{workspace_id}/conversations

Purpose:

  • list conversations within one workspace for the current identity

Query parameters:

  • limit (default 50, min 1, max 200)

  • offset (default 0)

Behavior:

  • requires active workspace membership

  • returns conversations created by the current identity

  • also returns legacy conversations that do not have created_by recorded yet

Success:

  • 200 OK

  • returns ConversationListResponse

GET /api/aibs/conversations/{conversation_id}

Purpose:

  • fetch one conversation if the current identity created it

Behavior:

  • requires workspace membership for the conversation’s workspace

  • requires the conversation creator after workspace membership is confirmed

  • legacy conversations with missing created_by remain readable by workspace members

Success:

  • 200 OK

  • returns ConversationResponse

PUT /api/aibs/conversations/{conversation_id}

Purpose:

  • rename a workspace-bound conversation record

Behavior:

  • loads the conversation through the backend-owned conversation service

  • rejects rename while workspace delete is already in progress

  • requires the conversation creator after workspace membership is confirmed

  • updates the conversation title and updated_at

Success:

  • 200 OK

  • returns ConversationResponse

DELETE /api/aibs/conversations/{conversation_id}

Purpose:

  • delete one workspace-bound conversation record

Behavior:

  • loads the conversation through the backend-owned conversation service

  • rejects delete while workspace delete is already in progress

  • requires the conversation creator after workspace membership is confirmed

  • removes only the lightweight conversation record

Success:

  • 204 No Content

GET /api/aibs/conversations/{conversation_id}/history

Purpose:

  • reload one conversation from persisted query and answer records

Behavior:

  • requires workspace membership for the conversation’s workspace

  • requires the conversation creator after workspace membership is confirmed

  • legacy conversations with missing created_by remain readable by workspace members

  • returns both grounded and insufficient turns truthfully

  • returns fallback conversation-context turns when published answer lineage exists

Success:

  • 200 OK

  • returns ConversationHistoryResponse

POST /api/aibs/documents

Purpose:

  • upload, register, and queue a new document for processing

Request:

  • multipart/form-data

  • fields:

    • workspace_id (required)

    • file (required)

    • title (optional)

Behavior:

  • validates upload size before reading

  • stages the file to disk

  • computes checksum

  • stores the managed file

  • creates a registered document record

  • submits (or reuses an active) ingestion job in OpenSearch before returning

  • rolls back registration if job submission fails

  • requires workspace owner, admin, or member

Success:

  • 201 Created

  • returns DocumentResponse

GET /api/aibs/documents/catalog

Purpose:

  • return a paged workspace document catalog for the source-list UI

Query parameters:

  • workspace_id (required)

  • limit (default 100, min 1, max 500)

  • offset (default 0)

  • q (optional metadata/title/search text, max 200)

  • language (optional ISO/language filter)

  • status (optional, repeatable document status filter)

Behavior:

  • requires any active workspace role

  • reads from the OpenSearch-backed document catalog projection

  • returns lightweight document metadata, not full aggregate JSON

  • summary describes the full workspace; page.total_matches describes the current filtered result set

Success:

  • 200 OK

  • returns DocumentCatalogResponse

GET /api/aibs/documents

Purpose:

  • list documents within one workspace through the legacy simple list route

Query parameters:

  • workspace_id (required)

  • limit (default 50, min 1, max 200)

  • offset (default 0)

Success:

  • 200 OK

  • returns DocumentListResponse

PATCH /api/aibs/documents/{document_id}/knowledge

Purpose:

  • enable or disable a document for assistant knowledge retrieval while keeping it visible as an uploaded workspace artifact

Request:

  • JSON body:

    • enabled (required boolean)

Behavior:

  • requires workspace owner or admin

  • disabled documents remain catalog-searchable and previewable unless the caller explicitly asks search to exclude them with include_disabled=false

  • disabled documents are excluded from assistant knowledge retrieval

Success:

  • 200 OK

  • returns DocumentResponse

GET /api/aibs/documents/{document_id}/snippets

Purpose:

  • return a small set of indexed chunk previews for a document

Query parameters:

  • workspace_id (required)

  • n (default 3, min 1, max 10)

Behavior:

  • requires any active workspace role

  • returns an empty list for documents that are not indexed/searchable yet

  • does not call the LLM

Success:

  • 200 OK

  • returns DocumentSnippetListResponse

GET /api/aibs/documents/{document_id}/preview

Purpose:

  • stream the original uploaded document for inline preview or download

Query parameters:

  • workspace_id (required)

  • download (default false; when true, uses attachment disposition)

Behavior:

  • requires any active workspace role

  • disabled knowledge documents remain previewable

  • inline preview is capped by AIBS_MAX_UPLOAD_SIZE_BYTES; download bypasses that preview cap

Success:

  • 200 OK

  • returns the file stream

GET /api/aibs/documents/{document_id}

Purpose:

  • fetch one document by id inside a specific workspace

Behavior:

  • enforces workspace membership

  • loads the document

  • enforces that the document belongs to the requested workspace

Success:

  • 200 OK

  • returns DocumentResponse

POST /api/aibs/documents/{document_id}/process

Purpose:

  • submit or reuse a durable ingestion job for a document (manual retry/recovery path)

Behavior:

  • requires workspace owner, admin, or member

  • rejects documents in draft, uploaded, or other invalid pre-registration states

  • creates a new ingestion job in OpenSearch or reuses the existing active job for the same document (no duplicate jobs per document)

  • returns immediately — actual parse/chunk/index work happens asynchronously in the ingestion worker loop

Success:

  • 202 Accepted

  • returns ProcessAcceptedResponse

Important note:

  • processing_started=false means an active job already existed and was reused, not that processing failed

  • job_id in the response identifies the OpenSearch job record for traceability

DELETE /api/aibs/documents/{document_id}

Purpose:

  • delete one document and its bounded indexed content

Behavior:

  • requires workspace owner or admin

  • rejects deletion if the document is currently in the in-flight processing registry

  • rejects deletion if the persisted document status is a processing state

Success:

  • 204 No Content

POST /api/aibs/chat/

Purpose:

  • answer a workspace-scoped question over the current conversation orchestration seam

Behavior:

  • enforces active workspace membership; viewers may ask questions

  • resolves or creates a real persisted conversation bound to the workspace

  • rejects explicit document ids that do not belong to the workspace

  • accepts execution_mode_override values auto, creative, or grounded (casual is accepted only as a legacy compatibility alias for creative)

  • streams an SSE response

Current note:

  • chat now runs through evidence-regime routing followed by workload planning

  • public evidence regimes are:

    • creative - evidence optional, with citations when source evidence is used

    • grounded - strict evidence required for factual claims

  • internal workload strategies are:

    • chat

    • chat_map_reduce

    • agent_map_refine_compose

  • turns can complete as:

    • creative

    • document_grounded

    • conversation_context

    • insufficient

  • the SSE contract includes query and answer ids plus answer-mode truth

Success:

  • 200 OK

  • returns text/event-stream

Response Models

WorkspaceResponse

Fields:

  • workspace_id

  • name

  • visibility

  • status

  • member_count

  • owner_count

  • created_at

  • updated_at

  • current_user_role

WorkspaceListResponse

Fields:

  • workspaces: list[WorkspaceResponse]

WorkspaceMemberResponse

Fields:

  • membership_id

  • user_id

  • role

  • joined_at

ConversationResponse

Fields:

  • conversation_id

  • workspace_id

  • title

  • created_by

  • created_at

  • updated_at

ConversationListResponse

Fields:

  • conversations: list[ConversationResponse]

ConversationHistoryResponse

Fields:

  • conversation_id

  • turns: list[ConversationHistoryTurnResponse]

ConversationHistoryTurnResponse

Fields:

  • query_id

  • workspace_id

  • conversation_id

  • question_text

  • query_status

  • answer_id

  • answer_text

  • publication_status

  • confidence_label

  • citations

  • is_fallback

  • grounded

  • asked_at

  • answered_at

DocumentResponse

Fields:

  • document_id

  • workspace_id

  • title

  • media_type

  • status

  • is_degraded

  • failure_reason

  • knowledge_enabled

  • ingestion_active

  • language

  • chunk_count

  • page_count

  • search_score

  • search_match_reasons

  • search_snippets

  • created_at

  • updated_at

DocumentListResponse

Fields:

  • documents: list[DocumentResponse]

DocumentCatalogResponse

Fields:

  • documents: list[DocumentResponse]

  • summary: DocumentCatalogSummaryResponse

  • page: DocumentCatalogPageResponse

Notes:

  • summary is workspace-wide, even when a search/filter is active.

  • page.total_matches is the result denominator for the current catalog/search request. For semantic and hybrid search, it can be bounded by the candidate window rather than an exact full-workspace count.

DocumentCatalogSummaryResponse

Fields:

  • total

  • ready

  • processing

  • queued

  • review

  • chunks

DocumentSnippetResponse

Fields:

  • chunk_id

  • title

  • text

  • page_start

  • page_end

  • match_reason

  • highlights

DocumentSnippetListResponse

Fields:

  • document_id

  • snippets: list[DocumentSnippetResponse]

ProcessAcceptedResponse

Fields:

  • document_id

  • status

  • processing_started

  • job_id (the OpenSearch ingestion job id; null when the route short-circuits before submission)

Error payload

The app maps AIBSError subclasses into JSON responses shaped like:

{
  "error": "Error message description",
  "code": "stable_error_code"
}

Typical status mapping:

  • 400 validation errors

  • 403 authorization failures

  • 404 missing entities

  • 409 duplicates / invalid state transitions

  • 422 invariant violations

  • 502 external service errors

  • 500 persistence and unexpected backend failures

Current Contract Boundaries

  • Workspace and conversation truth now live in backend-owned persistence.

  • Conversation reload is rebuilt from persisted QueryExecution and AnswerArtifact records rather than a separate transcript store.

  • Auth is active. Non-dev mode requires cookie-backed sessions from OpenSearch/Logserver credentials and explicit aibs-access.

  • Product administration requires both aibs-access and aibs-admin.

  • Workspace membership remains the workspace authorization source of truth.

  • Ingestion is a durable OpenSearch-backed job API with OCC-based claiming and lease reaping.

  • Document catalog/search reads are backed by a separate OpenSearch projection; document JSON remains the aggregate source of truth.

  • Smart document search is mode=hybrid; assistant-backed query expansion is guarded and best-effort inside that mode only.