Opbox

AI Assistant API

The AI assistant provides a conversational interface with full access to Opbox data via 129 built-in tools. It supports multiple AI model providers, real-time streaming responses, plan mode, saved prompts, @-mention entity references, and live UI refresh when the AI performs write operations.

Overview

  • Accessible via Cmd+K (or Ctrl+K) -> AI tab
  • Real-time streaming responses, displayed word by word
  • 129 tools for search, knowledge retrieval, data operations, user interaction, dashboards, files, and more
  • Support for multiple AI model providers
  • Conversation persistence with thread management
  • Page context awareness - AI knows which page you're viewing and can access relevant data automatically
  • Plan Mode: restricts AI to read-only tools; no writes possible even if requested
  • Saved Prompts: per-user library of reusable prompts (max 50) with usage tracking
  • @ Mentions: type @ in the chat input to search and attach entities (matters, forms, tables, documents, workflows, submissions) as context (max 10 references)
  • Live UI refresh: when the AI performs write operations (e.g. adding subtasks, completing steps), the host page automatically refreshes its data - no manual reload needed
  • Write limits per session and per day to prevent misuse
  • Security scanning on all tool results to detect and block injection attempts

Endpoints

MethodEndpointDescription
POST/api/ai/chatSend a message and stream AI response with tool execution
POST/api/integrations/ai/executeExecute a one-shot AI prompt (used by automation AI steps)
POST/api/ai/passport-ocrExtract structured data from passport images using AI vision
POST/api/ai/transcribeUpload an audio file and transcribe it (Whisper or WhisperX with speaker diarization)
GET/api/ai/transcriptsList the current user's own transcripts (private per-user)
GET/api/ai/transcripts/:idGet a single transcript by ID (must be owned by the requesting user)
DELETE/api/ai/transcripts/:idDelete a transcript (must be owned by the requesting user)

Chat History

MethodEndpointDescription
GET/api/ai/chatsList chat sessions
POST/api/ai/chatsCreate a new chat session
GET/api/ai/chats/:idGet a chat session with metadata
PATCH/api/ai/chats/:idUpdate a chat session (rename, archive)
DELETE/api/ai/chats/:idDelete a chat session and all its messages
GET/api/ai/chats/:id/messagesList messages in a chat session

Skills

MethodEndpointDescription
GET/api/ai/skillsList skills (max 50 per user)
POST/api/ai/skillsCreate a skill
DELETE/api/ai/skills/:idDelete a skill
POST/api/ai/skills/:idRecord usage of a skill

Chat Streaming

Sends a conversation to the AI and streams the response as Server-Sent Events (SSE). The AI can call tools to query and modify Opbox data, then continue generating text. The AI may call multiple tools per request to fulfil your query.

POST /api/ai/chat
Content-Type: application/json

{
  "messages": [
    { "role": "user", "content": "Summarise this matter and suggest next steps" }
  ],
  "provider": "anthropic",
  "pageContext": "/matters",
  "references": [
    { "id": "cm1abc...", "type": "matters", "title": "ACME Ltd Incorporation" }
  ]
}

Body Parameters

FieldTypeRequiredDescription
messagesarrayYesConversation history with role (user/assistant) and content
providerstringNo"anthropic" or "openai". Auto-resolves based on configured API keys.
pageContextstringNoCurrent page pathname (e.g. /matters/cm...). Used to provide the AI with awareness of the current page.
planModebooleanNoWhen true, the AI is restricted to read-only tools. Write operations are unavailable regardless of what the AI requests.
scopeToPagebooleanNoWhen true (and pageContext is set), the AI is instructed to focus on the current page's resource.
referencesarrayNoArray of { id, type, title } objects from @-mention selections. Entity content is fetched and provided to the AI as context. Supported types: matters, forms, tables, documents, workflows, submissions. Max 10 references.

Stream Events

The response is an SSE stream (text/event-stream). Each event is a JSON line:

Event TypeDescription
textChunk of assistant text content
text_deltaToken-level text delta (for real-time streaming)
tool_startTool execution started (includes tool name and input)
tool_resultTool execution finished - includes toolName, result, and isError. Successful write operations trigger a live UI refresh.
confirmation_requestAI is asking the user to confirm a write operation before proceeding. Includes message (description of the action) and actionDescription (short label). The UI renders an Approve/Deny dialog. User response is sent as a follow-up message.
question_requestAI is asking the user a clarifying question. Includes question and optional options array. The UI renders an inline input with optional quick-pick buttons.
errorError during processing
doneStream complete

Example Stream

data: {"type":"text_delta","content":"Here"}
data: {"type":"text_delta","content":" are"}
data: {"type":"text_delta","content":" your"}
data: {"type":"tool_start","toolName":"list_matters","toolId":"toolu_01...","input":{"status":"OPEN"}}
data: {"type":"tool_result","toolName":"list_matters","toolId":"toolu_01...","result":{...},"isError":false}
data: {"type":"text_delta","content":"You have 5 open matters..."}
data: {"type":"done"}

Available Tools (129)

The AI assistant has access to 129 tools across all major Opbox modules. Tools are automatically called by the AI based on user requests. Write operations use a confirm-then-act pattern - the AI calls ask_confirmation before mutating data, rendering an Approve/Deny dialog in the UI. Archive operations are intentionally excluded from the AI toolset - they are available in the UI only.

User Interaction

ToolDescription
ask_confirmationAsk the user to approve a write operation before proceeding. Renders an Approve/Deny dialog. The AI pauses until the user responds.
ask_questionAsk the user a clarifying question. Renders an inline input with optional quick-pick options. The AI pauses until the user answers.
ToolDescription
searchSearch across all entities (forms, matters, tables, documents, etc.)

Knowledge Retrieval (RAG)

ToolDescription
knowledge_searchHybrid semantic + full-text search across all org content (documents, comments, notes, transcripts, compliance exceptions). Returns ranked chunks with source metadata and relevance scores.
get_document_contentRetrieve full document content by ID for deeper context after a knowledge_search match. Returns complete structured JSON or plain text.
get_document_extractionsGet AI-extracted structured data (entities, key-value pairs) from a document.

Matters

ToolDescription
list_mattersList matters with filters (status, priority, board, assignee)
search_mattersFull-text search across matter titles, descriptions, and metadata
get_matterGet matter details with steps and properties
get_matter_by_numberLook up matter by number (e.g. MAT-0001)
create_matterCreate a new matter from a board
update_matterUpdate matter fields (title, priority, status, due date, tags)
complete_stepComplete a matter step - queued for confirmation
get_step_form_dataRetrieve current form field values for a FORM step
fill_step_formFill in form field values on a FORM step (user reviews and completes in UI)
reject_stepReject a matter step with optional reason - queued for confirmation
skip_stepSkip a matter step
reopen_stepReopen a completed or rejected step - queued for confirmation
assign_stepAssign a step to a user
update_step_configUpdate step configuration (name, description, required, assignee)
preview_step_documentPreview a document template step with current matter data
scaffold_form_from_packAuto-generate a form from a template pack definition
add_commentAdd a comment to a matter step
update_matter_metadataUpdate board property values
add_line_itemAdd a line item with pricing
list_line_itemsList matter line items
update_line_itemUpdate a line item
list_subtasksList subtasks for a step
add_subtaskAdd a subtask to a step
complete_subtaskToggle a subtask between completed and incomplete
update_subtaskUpdate a subtask title or assignee
delete_line_itemArchive (soft-delete) a line item - queued for confirmation
get_matter_documentsList documents attached to a matter

Boards

ToolDescription
list_boardsList all matter templates/boards
get_boardGet board details with steps and settings
list_board_propertiesList metadata field definitions for a board
list_labelsGet org-wide matter label suggestions

Forms & Submissions

ToolDescription
list_formsList forms with optional status filter
get_formGet form details with field definitions
create_formCreate a new form with fields
list_submissionsList submissions with filters
get_submissionGet full submission data
approve_submissionApprove a pending submission (destructive)
reject_submissionReject a pending submission (destructive)

Tables & Data

ToolDescription
list_tablesList all tables in the workspace
create_tableCreate a new table with optional columns
get_table_detailsGet full table schema with columns and metadata
update_tableUpdate table name or description (ADMIN/OWNER)
delete_tableDelete a table permanently (ADMIN/OWNER)
get_table_rowsQuery table rows with server-side search and pagination
summarize_tableGet aggregate statistics for a table (row count, column distributions)
create_rowCreate a new table row
update_rowUpdate an existing table row
patch_rowPartially update specific fields on a row without replacing all data
delete_rowDelete a row from a table
bulk_create_rowsCreate up to 50 rows in one call
bulk_update_rowsUpdate multiple rows in a single call (up to 50)
create_columnAdd a column to a table (18 types, ADMIN/OWNER)
update_columnUpdate column name or config (ADMIN/OWNER)
delete_columnDelete a column from a table (ADMIN/OWNER)

Documents & Workflows

ToolDescription
list_documentsList documents in the knowledge base
get_documentGet document content (truncated to 500 chars for safety)
update_documentUpdate a document's content (full structured JSON) - queued for confirmation
patch_documentPartially update document metadata (title, status, parent) without replacing content
list_workflowsList automation workflows
execute_workflowExecute an automation - queued for confirmation

Notifications & Organisation

ToolDescription
get_notificationsGet recent notifications
mark_notifications_readMark notifications as read
get_dashboard_statsGet dashboard statistics
list_membersList workspace members

Transcripts (Private Per-User)

ToolDescription
list_my_transcriptsList the current user's own voice transcripts (private)
get_my_transcriptGet full text of a transcript owned by the current user

API Access

ToolDescription
list_api_endpointsDiscover available API endpoints (read-only)
call_api_endpointCall any Opbox GET endpoint - restricted to read-only (GET) requests only

Dashboard Tools

ToolDescription
list_dashboard_widgetsList all widgets on a dashboard
add_dashboard_widgetAdd a new widget to a dashboard with full config
update_dashboard_widgetUpdate an existing widget (type, data source, appearance, layout)
remove_dashboard_widgetRemove a widget from a dashboard
bulk_update_dashboardBatch update multiple widgets and dashboard settings in one call
set_dashboard_configReplace the entire dashboard config (widgets, filters, auto-refresh)
get_dashboard_statsGet summary statistics for the workspace dashboard

SQL Query Library

ToolDescription
execute_sqlExecute a read-only SQL query against the workspace database
save_sql_querySave a SQL query to the user's library for later reuse
list_saved_queriesList saved SQL queries for the current user
run_saved_queryExecute a previously saved SQL query by ID

File Registry

ToolDescription
list_files_for_entityList files linked to a specific entity (document, form, etc.)
list_files_for_matterList all files associated with a matter and its steps
list_files_for_rowList files linked to a specific table row
get_file_recordGet metadata for a single file record by ID
link_file_to_entityCreate a link between an existing file and an entity

Identity & Access

ToolDescription
list_access_grantsList cross-workspace access grants for an entity
list_workspace_grantsList all access grants visible to the current workspace
get_document_presenceCheck if a document exists across workspaces (presence only, no content)
resolve_row_identityResolve a table row to a global identity
get_file_version_historyGet version history for a file record
get_identity_review_queueList identity matches pending review
resolve_identity_reviewApprove or reject an identity match review
get_open_escalationsList open escalations requiring attention
resolve_escalationResolve an open escalation with a decision and notes
check_file_sensitivityCheck sensitivity classification of a file
get_registry_coverageGet file registry coverage statistics for the workspace
request_file_accessRequest access to a file from another workspace
get_extraction_qualityGet quality metrics for document extractions

Ownership & Corporate Structure

ToolDescription
get_ownership_chainTrace the ownership chain from entity to ultimate parent
get_corporate_family_treeGet the full corporate group tree for an entity
detect_circular_ownershipDetect circular ownership references in entity structures
get_ubosGet ultimate beneficial owners (UBOs) for an entity
check_ubo_mismatchesCompare declared vs computed UBOs and flag discrepancies

Registers & Compliance

ToolDescription
get_registerGet a statutory register (shareholders, directors, etc.) for an entity
get_register_historyGet historical changes to a register with audit trail
get_stakeholder_exposureGet cross-entity exposure summary for a stakeholder
find_shared_stakeholdersFind stakeholders shared across multiple entities
detect_conflicts_of_interestDetect potential conflicts of interest based on stakeholder overlaps
get_compliance_calendarGet upcoming compliance deadlines and filing dates
get_kyc_expiry_reportGet KYC document expiry report across entities
get_entity_compliance_summaryGet overall compliance health summary for an entity

Entity File Intelligence

ToolDescription
get_entity_files_deepDeep file aggregation for a CSP entity - traverses direct files, matter files, and stakeholder files
get_individual_files_deepDeep file aggregation for a CSP individual - traverses direct files, matter files, and bridged KYC docs
get_stakeholder_file_timelineChronological cross-entity file timeline for a stakeholder across all roles and matters
link_entity_to_matterLink a CSP entity to a matter
link_individual_to_matterLink a CSP individual to a matter
sync_matter_entity_linksSync entity links from matter metadata and linked records
backfill_matter_filesBackfill file propagation for an existing matter
bridge_kyc_documentsBridge KYC documents to the file registry for unified search

Self-Knowledge

ToolDescription
search_system_docsSearch Opbox's own product documentation by keyword. Returns relevant sections with relevance scoring.
embed_system_docsIndex product documentation for semantic search.

Self-knowledge tools enable the AI to answer questions about Opbox's own architecture, features, and data model. REST equivalents are available at GET /api/docs/search and POST /api/docs/embed. See the Intelligence Architecture page for details.

For a complete per-tool reference with parameter types and descriptions, see the AI Tools Reference page.

Parallel Tool Execution

The AI can call multiple tools in a single response. Independent tool calls execute concurrently on the server for maximum speed. The chat UI groups multiple tool calls into a single collapsible disclosure:

  • Single tool call: Shown inline with status indicator and label (expandable for input/result)
  • Multiple tool calls: Collapsed into "N tool calls" - click to expand and see each call individually, click a call to see its input/result
  • During streaming: Tool group auto-expands to show progress; auto-collapses when all tools complete successfully
  • Error handling: Failed tool count shown in the collapsed summary; group stays expanded if any tool errored

Chat Thread Management

Conversations are persisted server-side as threads. Each thread stores its messages with tool call history.

MethodEndpointDescription
GET/api/ai/chatsList chat threads for the current user
POST/api/ai/chatsCreate a new chat thread
GET/api/ai/chats/:idGet a thread with its messages
PATCH/api/ai/chats/:idArchive a chat thread
POST/api/ai/chats/:id/messagesPersist messages (user + assistant) to a thread

Confirm-Then-Act Pattern

Before performing any write operation, the AI calls ask_confirmation which renders an Approve / Deny dialog in the chat UI. The agentic loop pauses until the user responds. If approved, the AI proceeds with the action in the next turn. If denied, it acknowledges and stops. This replaces the previous apply: prefix requirement.

Similarly, ask_question renders an inline input when the AI needs clarification. The user can type a response or click a suggested option.

All write operations are scoped to the authenticated user's active workspace and logged in the audit trail.

Archive operations (archive_matter, archive_table, etc.) are not available to the AI - they are human-only actions accessible only through the Opbox UI.

Security Model

ControlValueDescription
Session write limitPer sessionMaximum mutating tool calls per chat session. Resets on new thread.
Daily write limitPer userPer-user daily write cap across all sessions. Skipped in Plan Mode.
Context windowRecent messagesOnly recent messages are sent to the AI per request. Full thread is preserved.
Injection scanningAutomaticTool results are scanned for injection attempts. Detected injections are sanitised before the AI processes them.
API endpoint accessRead-onlyThe call_api_endpoint tool is restricted to GET requests. Sensitive endpoints are blocked.
SQL queriesRead-only, sandboxedRead-only SQL execution with workspace isolation, query timeout, and row limits. ADMIN role required.
Cell lockingEnforcedLocked cells cannot be modified by the AI or API updates.
Content truncationAutomaticDocument content and tool results are truncated to safe limits.

Plan Mode

Plan Mode restricts the AI to read-only tools. When planMode: true is sent, write tools are not available to the AI and cannot be called. Toggle available in the chat UI as a "Plan" pill below the input box.

Page Context Preloading

When a user sends their first message from a matter or document page, the current resource's data is automatically preloaded for the AI. This eliminates the need for extra lookups before performing operations, significantly reducing latency.

Matter pages preload: matter title, status, priority, assignee, due date, labels, board name, board properties (with current values), step pipeline (with stepId for each step), form titles for FORM steps, and APPROVAL step -> form linkage. The AI can use preloaded step IDs directly for add_subtask, complete_step, assign_step, etc. without calling get_matter first.

Document pages preload: document title, content (first 3000 chars), and custom metadata properties.

Form Awareness in Matters

The AI understands which specific forms are associated with matter steps:

FORM steps: the AI sees the assigned form title (e.g. "KYC Questionnaire") for both pending and completed FORM steps. Multi-form steps with formIds show all available form titles. Completed FORM steps also include collected field data.

APPROVAL steps: the AI sees which FORM step an approval reviews (e.g. "reviews: Collect KYC - form: KYC Questionnaire"), derived from the reviewFormStepIndex in the approval step config.

Live UI Refresh

When the AI performs write operations via the sidebar chat, the host page automatically refreshes its data without requiring a manual page reload. For example, completing a step or adding a subtask via AI chat will immediately update the matter detail view.

Saved Prompts

Per-user reusable prompt library backed by Knowledge Base documents. Prompts are stored as full KB documents inside a "Prompts" system folder (auto-created on first KB visit alongside the Transcripts folder). Users can save frequently-used inputs from the chat UI, browse and edit them as rich documents in the Knowledge Base, and organise them into subfolders. Max 50 prompts per user (counted across the entire Prompts folder tree).

MethodEndpointDescription
GET/api/ai/skillsList skill documents from the Skills KB folder (including subfolders), newest first. Content extracted as plain text from structured JSON.
POST/api/ai/skillsCreate a skill document in the Skills KB folder - body: { title, content } (title max 120 chars, content max 5 000 chars; 50-skill limit). Plain text converted to structured JSON.
DELETE/api/ai/skills/:idDelete a skill document (must be under the Skills folder tree in the current org)
POST/api/ai/skills/:idMark skill as used - body: { action: "use" } (no-op, kept for API compatibility)

Admin: Security Events (OWNER only)

Query the workspace's security event log. Events are recorded automatically by the security monitoring system. Requires OWNER role.

GET /api/admin/security-events?type=AI_INJECTION_ATTEMPT&limit=50&cursor=cm...
Query ParamDescription
typeFilter by event type: AI_INJECTION_ATTEMPT, AI_RATE_LIMIT, CSRF_VIOLATION, LOGIN_FAILURE, RATE_LIMIT
cursorEvent ID for cursor-based pagination (from previous response nextCursor)
limitResults per page (max 100, default 50)
{
  "events": [
    {
      "id": "cm...",
      "type": "AI_INJECTION_ATTEMPT",
      "detail": "Injection pattern detected in tool result",
      "metadata": { "toolName": "get_document", "pattern": "\\[INST\\]" },
      "ipAddress": "1.2.3.4",
      "createdAt": "2026-02-17T10:30:00.000Z",
      "user": { "name": "Jane Doe", "email": "jane@example.com" }
    }
  ],
  "total": 42,
  "nextCursor": "cm..."
}

The admin view at Settings -> Security -> Events surfaces this data with filter tabs and an injection alert banner.

Admin: RAG Embeddings (ADMIN / OWNER)

Monitor and manage the RAG (Retrieval-Augmented Generation) embedding pipeline. Content from documents, comments, notes, transcripts, and compliance exceptions is automatically chunked and embedded for semantic search.

Get Status

GET /api/admin/rag?sourceType=DOCUMENT
{
  "ragEnabled": true,
  "embeddingModel": "text-embedding-3-small",
  "statusBySourceType": {
    "DOCUMENT": { "COMPLETED": 42, "PENDING": 2 },
    "MATTER_COMMENT": { "COMPLETED": 15 }
  },
  "chunksBySourceType": {
    "DOCUMENT": { "chunks": 210, "tokens": 48500 }
  },
  "recentFailures": []
}

Trigger Backfill (OWNER only)

POST /api/admin/rag
Content-Type: application/json

{ "sourceType": "DOCUMENT" }  // Optional - omit to backfill all types

Backfill runs asynchronously. Supported source types: DOCUMENT, MATTER_COMMENT, TRANSCRIPT, SUBMISSION_NOTE, REGULATOR_COMMENT, TABLE_ROW_NOTE, COMPLIANCE_EXCEPTION.

AI Execute (Automations)

One-shot AI prompt execution used by automation AI steps and the workflow builder test button. Supports both Anthropic and OpenAI providers. API keys are configured in user preferences (Settings -> AI).

POST /api/integrations/ai/execute
Content-Type: application/json

{
  "provider": "anthropic",
  "model": "claude-sonnet-4-5-20250929",
  "prompt": "Summarize this form submission: ...",
  "systemPrompt": "You are a helpful assistant.",
  "temperature": 0.7,
  "maxTokens": 1024
}

Response

{
  "success": true,
  "requestId": "ai-1708000000-abc1234",
  "provider": "anthropic",
  "model": "claude-sonnet-4-5-20250929",
  "response": {
    "content": "The form submission contains...",
    "finishReason": "end_turn"
  },
  "usage": {
    "promptTokens": 150,
    "completionTokens": 200,
    "totalTokens": 350
  }
}

Provider Configuration

AI providers are configured in Settings -> AI (requires ADMIN or OWNER role). The system supports two providers:

ProviderModelsEnv Variable
AnthropicClaude Sonnet 4.5, Claude Haiku 4.5, Claude Opus 4.6ANTHROPIC_API_KEY
OpenAIGPT-5.2, o3, GPT-4o, GPT-4o Mini, o3-miniOPENAI_API_KEY

Keys configured in Settings -> AI take priority over environment variables. For automation AI steps, the system loads the org admin/owner's configured keys.

Passport OCR

AI-powered passport data extraction using vision models. Extracts structured data from passport images including name, nationality, date of birth, document number, expiry date, and MRZ data.

POST /api/ai/passport-ocr
Content-Type: application/json

{
  "imageUrl": "https://example.com/passport-scan.jpg"
}
{
  "success": true,
  "data": {
    "fullName": "JOHN DOE",
    "nationality": "United Kingdom",
    "dateOfBirth": "1985-03-15",
    "documentNumber": "AB1234567",
    "expiryDate": "2030-01-20",
    "sex": "M",
    "mrzLine1": "P<GBRDOE<<JOHN<<<<<<<<<<<<<<<<<<<<<<<<",
    "mrzLine2": "AB12345670GBR8503151M3001207<<<<<<<<<<<04"
  }
}

Voice Transcription

Transcribe audio files (voice memos, recordings) using Whisper (cloud) or WhisperX (local with speaker diarization). The provider is configured in Settings -> AI -> Transcription.

Privacy: Transcripts are private to the uploading user. The list and detail endpoints filter by the authenticated user's ID - users can only see and manage their own transcripts. The AI assistant accesses transcripts via dedicated list_my_transcripts / get_my_transcript tools which enforce the same per-user scoping.

Transcription Providers

ProviderSpeaker DiarizationRequirements
Whisper (cloud)No - plain text onlyOpenAI API key
WhisperX (local)Yes - timestamped segments with speaker labelsPython 3, pip install whisperx, HuggingFace token (HF_TOKEN), WHISPERX_ENABLED=true

Provider selection: auto uses WhisperX if available (enabled + installed), otherwise Whisper. Force a specific provider via transcriptionProvider in user AI preferences.

Upload & Transcribe

POST /api/ai/transcribe
Content-Type: multipart/form-data

file: <audio file (max 1GB)>
title: "Lee & Will"  // optional - user-chosen display name

Supported formats: .m4a, .mp3, .wav, .webm, .ogg, .flac, .mp4, .qta (Apple Voice Memos - auto-converted to m4a). The UI shows a naming dialog on file selection - the title defaults to the filename (minus extension) and is used as the Knowledge Base document name with a date prefix (e.g. "18 February 2026 - Lee & Will").

// Response (WhisperX - with speaker diarization)
{
  "id": "cm...",
  "filename": "meeting.m4a",
  "title": "Lee & Will",
  "text": "Hello everyone, let's get started...",
  "language": "en",
  "durationSecs": 120.5,
  "provider": "whisperx",
  "speakerCount": 3,
  "segments": [
    { "start": 0.5, "end": 3.2, "text": "Hello everyone, let's get started.", "speaker": "SPEAKER_00" },
    { "start": 3.8, "end": 7.1, "text": "Thanks for joining.", "speaker": "SPEAKER_01" }
  ],
  "createdAt": "2026-02-18T10:30:00.000Z"
}

// Response (Whisper - plain text, no segments)
{
  "id": "cm...",
  "filename": "recording.m4a",
  "title": null,
  "text": "Hello, this is a transcription of...",
  "language": "english",
  "durationSecs": 42.5,
  "provider": "openai",
  "speakerCount": null,
  "segments": null,
  "createdAt": "2026-02-18T10:30:00.000Z"
}

List Transcripts

GET /api/ai/transcripts?search=meeting&page=1&limit=20
{
  "transcripts": [
    {
      "id": "cm...",
      "filename": "meeting-notes.m4a",
      "title": "Lee & Will",
      "fileSize": 1048576,
      "mimeType": "audio/mp4",
      "durationSecs": 120.3,
      "text": "...",
      "language": "en",
      "status": "completed",
      "provider": "whisperx",
      "speakerCount": 2,
      "segments": [...],
      "createdAt": "2026-02-17T10:30:00.000Z",
      "user": { "name": "John Doe", "email": "john@example.com" }
    }
  ],
  "total": 1,
  "page": 1,
  "totalPages": 1
}

Response Fields

FieldTypeDescription
titlestring | nullUser-chosen display name set at upload time. Null if not provided. Used as the KB document title with a date prefix (e.g. "18 February 2026 - Lee & Will"). Falls back to filename (minus extension) when null.
providerstring | null"openai" or "whisperx". Null for legacy transcripts.
speakerCountnumber | nullNumber of unique speakers detected. Only populated by WhisperX.
segmentsarray | nullArray of { start, end, text, speaker } objects with timestamps in seconds. Only populated by WhisperX.

Get / Delete Transcript

GET /api/ai/transcripts/:id     // Returns full transcript record with segments
DELETE /api/ai/transcripts/:id  // Deletes the transcript

Custom System Prompt

Admins can configure a custom system prompt in Settings -> AI that is prepended to the AI assistant's built-in instructions. This allows customising the assistant's behaviour, tone, and domain knowledge for your workspace. Maximum 5,000 characters.

The custom prompt is applied to the Spotlight AI chat only (not to automation AI steps, which use their own per-step prompt configuration in the workflow builder).

Tool Result Entity Cards

When the AI assistant calls read-only tools that return structured entity data, the results are rendered as clickable inline entity cards below the tool call indicator. Each card shows the entity icon, title, and metadata chips (status, priority, assignee, board name, due date, etc.).

Mapped Tools

The following 12 read-only tools produce entity cards. Write/action tools (e.g. create_matter, approve_submission) display only the tool badge.

ToolEntity TypeCard Metadata
list_matters / get_matterMatterStatus, priority (with colour dot), board name, assignee, due date (red if overdue)
list_forms / get_formFormStatus, submission count
list_submissions / get_submissionSubmissionStatus, form title, submitter name
list_tablesTableCategory (System/Form/User), row count, column count
list_documents / get_documentDocumentTitle
list_workflowsWorkflowStatus
searchSearch ResultEntity type badge, status from metadata

Card Behaviour

Cards are clickable - clicking navigates to the entity detail page and closes the Spotlight dialog. List results show a maximum of 5 cards with a "Show N more" toggle to expand. Cards render in both the inline Spotlight AI chat (compact mode) and the standalone AI chat panel.

Chat History

Conversations are persisted to the database with per-user isolation. Each chat session stores its messages, provider, and page context. Sessions are auto-created when sending the first message. The last 25 messages are sent per request (compaction).

// List chat sessions
GET /api/ai/chats

// Response
{
  "chats": [
    {
      "id": "cm...",
      "title": "Summarise ACME matter",
      "createdAt": "2026-02-19T10:00:00.000Z",
      "updatedAt": "2026-02-19T10:05:00.000Z",
      "messageCount": 8
    }
  ]
}

// Get messages for a session
GET /api/ai/chats/:id/messages

// Delete a session
DELETE /api/ai/chats/:id

Skills

Per-user library of reusable skills - instructions, playbooks, and saved prompts (max 50). Skills are stored as Knowledge Base documents in a private "Skills" system folder. They are Document records with plain text content and are also discoverable by the AI via the list_skills and get_skill tools.

// List skills
GET /api/ai/skills

// Response
[
  {
    "id": "cm...",
    "title": "Summarise matter progress",
    "content": "Give me a summary of the current matter...",
    "createdAt": "2026-02-18T09:00:00.000Z"
  }
]

// Create a skill
POST /api/ai/skills
{ "title": "Weekly review", "content": "Summarise all active matters..." }

// Delete a skill
DELETE /api/ai/skills/:id

// Record usage
POST /api/ai/skills/:id
{ "action": "use" }

AI Agent (Autonomous Worker)

Server-side autonomous task processor that executes assigned tasks with configurable autonomy levels and tool access controls.

ControlDescription
Autonomy levelsConfigurable autonomy levels control which tools the agent can access. Default is read-only.
API key managementAPI key creation requires ADMIN/OWNER role with validated autonomy level
Injection scanningTool results are scanned for injection attempts and sanitised automatically
Task depth limitPrevents runaway self-spawning task chains
Task timeoutEach task has a maximum execution time
Concurrency capLimited concurrent task execution
Rate limitingPer-tool and per-key rate limits protect against overuse
Cost trackingPer-task cost tracking with budget checks before execution

AI Cost Control

Every LLM call records cost to the AiCostLedger with atomic budget snapshot upserts. Per-workspace monthly budgets with configurable hard cap and soft limit.

FeatureDescription
Atomic recording$transaction() creates ledger entry + upserts monthly snapshot in one operation
Budget gatecheckBudget() pre-call check with hard cap and configurable soft limit percentage
Fail-openCost recording and budget checks never block LLM calls on error - availability over consistency
ReconciliationreconcileBudgetSnapshot() detects drift between snapshot totals and ledger aggregates, auto-repairs
Key source trackingDistinguishes SERVER_KEY, WORKSPACE_KEY, USER_KEY - user keys bypass budget by default
Daily usagegetWorkspaceDailyUsage() for admin dashboard charts, getTopUsersBySpend() for user breakdown

Transcript Titling

When uploading audio for transcription, an optional title field can be provided via the upload form. The title is stored on the Transcript model and used when syncing to the Knowledge Base (format: "DD Month YYYY - Title"). Transcripts are auto-labeled with the transcript label in the KB. Searchable by title via GET /api/ai/transcripts?search=....

POST /api/ai/transcribe
Content-Type: multipart/form-data

file: <audio file>
title: "Client Meeting - ACME Ltd"     // optional
provider: "openai"                      // or "whisperx"

// Response includes transcript ID and KB document ID
{
  "id": "cm...",
  "text": "...",
  "title": "Client Meeting - ACME Ltd",
  "documentId": "cm..."               // KB page created
}