{"openapi":"3.1.0","info":{"title":"Blockbrain | Agentic","version":"canary","description":"API documentation for the Agentic API service."},"paths":{"/v1/api/memory/threads/{threadId}/messages":{"get":{"tags":["Memory"],"description":"Retrieve messages from a specific thread (last 50 messages)","responses":{"200":{"description":"Messages retrieved successfully (returns empty arrays if thread not found)"},"401":{"description":"Unauthorized - missing or invalid access token"},"500":{"description":"Internal server error"},"503":{"description":"Memory service temporarily unavailable"}}},"post":{"tags":["Memory"],"description":"Save messages to a specific thread","responses":{"200":{"description":"Messages saved successfully"},"400":{"description":"Bad request - invalid body"},"401":{"description":"Unauthorized - missing or invalid access token"},"500":{"description":"Internal server error"},"503":{"description":"Memory service temporarily unavailable"}}},"delete":{"tags":["Memory"],"description":"Delete all messages from a specific thread","responses":{"200":{"description":"All messages deleted successfully"},"401":{"description":"Unauthorized - missing or invalid access token"},"404":{"description":"Thread not found or user does not have access"},"500":{"description":"Internal server error"},"503":{"description":"Memory service temporarily unavailable"}}},"servers":[{"url":"/"}]},"/v1/api/memory/threads/{threadId}/messages/find":{"get":{"tags":["Memory"],"description":"Find messages in a thread by metadata fields or text content","responses":{"200":{"description":"Matching messages returned (empty array if none found)"},"401":{"description":"Unauthorized - missing or invalid access token"},"404":{"description":"Thread not found or user does not have access"},"500":{"description":"Internal server error"},"503":{"description":"Memory service temporarily unavailable"}}},"servers":[{"url":"/"}]},"/v1/api/memory/threads/{threadId}/messages/{messageId}":{"delete":{"tags":["Memory"],"description":"Delete a specific message from a thread","responses":{"200":{"description":"Message deleted successfully"},"401":{"description":"Unauthorized - missing or invalid access token"},"404":{"description":"Thread not found or user does not have access"},"500":{"description":"Internal server error"},"503":{"description":"Memory service temporarily unavailable"}}},"patch":{"tags":["Memory"],"description":"Update the content of a specific message in a thread","requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"parts":{"type":"array","description":"The message parts (text, images, files, etc.)","items":{"type":"object","description":"A message part. Must include a \"type\" field. Shape varies by type (e.g. text, reasoning, tool-invocation, image, file).","additionalProperties":true,"required":["type"]}}},"required":["parts"]}}}},"responses":{"200":{"description":"Message updated successfully"},"400":{"description":"Bad request - invalid body"},"401":{"description":"Unauthorized - missing or invalid access token"},"404":{"description":"Resource not found. Possible causes: thread does not exist, user does not have access to the thread, message does not exist, or message does not belong to the specified thread."},"500":{"description":"Internal server error"},"503":{"description":"Memory service temporarily unavailable"}}},"servers":[{"url":"/"}]},"/v1/api/agents":{"get":{"tags":["Agents"],"description":"Retrieve list of available agents with their capabilities","parameters":[{"name":"name","in":"query","description":"Filter agents by name (case-insensitive substring match)","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"Agents retrieved successfully"},"401":{"description":"Unauthorized - missing or invalid access token"},"500":{"description":"Internal server error"}}},"servers":[{"url":"/"}]},"/v1/api/models":{"get":{"tags":["Models"],"description":"List all available LiteLLM models with their display metadata","responses":{"200":{"description":"List of available models","content":{"application/json":{"schema":{"type":"object","properties":{"items":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"displayName":{"type":"string"},"mode":{"type":"string"},"supportsToolUse":{"type":"boolean"},"supportsVision":{"type":"boolean"},"maxInputTokens":{"type":"number"},"maxOutputTokens":{"type":"number"},"tags":{"type":"array","items":{"type":"string"}}}}},"total":{"type":"number"}}}}}}}},"servers":[{"url":"/"}]},"/v1/api/presentation/templates/{templateId}/preview":{"get":{"tags":["Presentation"],"description":"Get SVG previews for a presentation template. Resolves built-in templates first, then falls back to the calling user's uploaded templates — the local Postgres registry, or the integrations template API when `agent.template-api-loader` is ON.","parameters":[{"name":"templateId","in":"path","required":true,"schema":{"type":"string"},"description":"Template identifier (e.g., \"mckinsey\", \"google_style\", or a user-uploaded slug)"}],"responses":{"200":{"description":"Template SVG previews"},"401":{"description":"Unauthorized"},"404":{"description":"Template not found or not enabled for this organization"}}},"servers":[{"url":"/"}]},"/v1/api/presentation/templates/pipeline":{"post":{"tags":["Templates"],"description":"Start the template pipeline for a PPTX file. The endpoint validates the request, acknowledges with 202, and runs the (multi-minute) pipeline asynchronously — it downloads the file from the internal media-server via M2M, builds the template, and uploads the bundle. `templateMode` selects the pipeline: `mirror` (default) reproduces the slides verbatim; `fidelity` templatizes them into reusable layouts. Completion or failure is reported back to integrations via the internal pipeline callback keyed by jobId; this endpoint does NOT return the pipeline result inline.","requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"fileKey":{"type":"string","description":"Media-server key of the uploaded PPTX file"},"displayName":{"type":"string"},"category":{"type":"string","enum":["brand","general","scenario","government","special"]},"sourceName":{"type":"string"},"orgId":{"type":"string","description":"Organization ID for M2M download (X-Acting-As-Org-Id)"},"userId":{"type":"string","description":"User ID for M2M download (X-Acting-As-User-Id)"},"jobId":{"type":"string","description":"Integrations upload-job id; echoed to the completion callback for correlation"},"templateMode":{"type":"string","enum":["fidelity","mirror"],"description":"Pipeline selector; defaults to 'mirror' when omitted."}},"required":["fileKey","displayName","category","sourceName","orgId","userId","jobId"]}}}},"responses":{"202":{"description":"Pipeline accepted — runs asynchronously; result delivered via the integrations callback"},"400":{"description":"Missing or invalid fields"},"401":{"description":"Missing or invalid Zitadel bearer token"},"500":{"description":"Failed to accept the pipeline request"}}},"servers":[{"url":"/"}]},"/v1/api/custom-agents/{customAgentId}/export":{"post":{"tags":["Custom Agents"],"description":"Export a custom agent as a GitHub issue for conversion to predefined agent","requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"reason":{"type":"string","description":"Reason for exporting this custom agent"}},"required":["reason"]}}}},"responses":{"200":{"description":"Custom agent exported successfully as GitHub issue"},"400":{"description":"Invalid request body"},"401":{"description":"Unauthorized - missing or invalid access token"},"403":{"description":"Forbidden - export is restricted to Blockbrain-internal callers when the agent.restrict-custom-agent-export kill switch is enabled"},"500":{"description":"Internal server error"}}},"servers":[{"url":"/"}]},"/v1/api/memory/threads":{"post":{"tags":["Memory"],"description":"Create a new conversation thread with optional custom ID","requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"threadId":{"type":"string","description":"Optional custom ID for the thread (auto-generated if not provided)"},"botId":{"type":"string","description":"The ID of the bot/agent associated with this thread"},"dataRoomId":{"type":"string","description":"Optional ID of the data room to associate with this thread"}},"required":["botId"]}}}},"responses":{"201":{"description":"Thread created successfully"},"400":{"description":"Invalid request body or missing required fields"},"401":{"description":"Unauthorized - missing or invalid access token"},"409":{"description":"Thread with specified ID already exists"},"500":{"description":"Internal server error"},"503":{"description":"Memory service temporarily unavailable"}}},"servers":[{"url":"/"}]},"/v1/api/memory/threads/{threadId}":{"get":{"tags":["Memory"],"description":"Retrieve a specific thread by ID","responses":{"200":{"description":"Thread retrieved successfully (returns null if not found or unauthorized)"},"401":{"description":"Unauthorized - missing or invalid access token"},"500":{"description":"Internal server error"},"503":{"description":"Memory service temporarily unavailable"}}},"servers":[{"url":"/"}]},"/v1/api/memory/threads/{threadId}/usage":{"get":{"tags":["Memory"],"description":"Retrieve token usage and remaining context tokens from the last step of a thread","parameters":[{"name":"agentId","in":"query","required":false,"schema":{"type":"string"},"description":"Agent ID. Used to resolve the model context limit for new threads. For agents with a static model (e.g. Slack agent), the model is resolved automatically. For the custom agent, also pass modelGroup."},{"name":"modelGroup","in":"query","required":false,"schema":{"type":"string"},"description":"LiteLLM model group override. Required for custom-agent where the model is bot-specific (e.g. \"azure-gpt-41\"). Takes precedence over the model resolved from agentId."}],"responses":{"200":{"description":"Usage retrieved successfully (returns null fields if no usage data found)"},"401":{"description":"Unauthorized - missing or invalid access token"},"404":{"description":"Thread not found or does not belong to the user"},"500":{"description":"Internal server error"},"503":{"description":"Memory service temporarily unavailable"}}},"servers":[{"url":"/"}]},"/v1/api/memory/threads/{threadId}/working-memory":{"get":{"tags":["Memory"],"description":"Retrieve working memory for a specific thread","responses":{"200":{"description":"Working memory retrieved successfully"},"401":{"description":"Unauthorized - missing or invalid access token"},"404":{"description":"Thread or working memory not found"},"503":{"description":"Memory service temporarily unavailable"}}},"put":{"tags":["Memory"],"description":"Set or update the working memory for a specific thread","requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"workingMemory":{"type":"string","description":"The working memory content to set for the thread"}},"required":["workingMemory"]}}}},"responses":{"200":{"description":"Working memory updated successfully"},"400":{"description":"Invalid request body"},"401":{"description":"Unauthorized - missing or invalid access token"},"404":{"description":"Thread not found"},"500":{"description":"Internal server error"},"503":{"description":"Memory service temporarily unavailable"}}},"servers":[{"url":"/"}]},"/v1/api/memory/threads/{threadId}/tool-approval-mode":{"patch":{"tags":["Memory"],"summary":"Set the tool-approval mode for a thread (PDEV-4694)","description":"Persist `metadata.toolApprovalMode` on the chat thread. When 'auto', the streaming runtime strips the require-approval marker for write tools in this thread. The mode is honoured only when the `agent.tool-approval-overrides` rollout flag is enabled and the global kill-switch `botticelli.tool-approval.enable` permits the runtime gate.","requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"mode":{"type":"string","enum":["auto","manual"],"description":"Approval mode: `auto` skips the dialog, `manual` keeps the per-tool default."}},"required":["mode"]}}}},"responses":{"200":{"description":"Mode updated"},"400":{"description":"Invalid mode value"},"401":{"description":"Unauthorized"},"404":{"description":"Thread not found"},"500":{"description":"Internal server error"},"503":{"description":"Memory service temporarily unavailable"}}},"servers":[{"url":"/"}]},"/v1/api/memory/threads/{threadId}/data-retention":{"delete":{"tags":["Memory"],"description":"Delete a thread for data retention purposes (requires secret key authorization)","x-auth-bypass":true,"responses":{"200":{"description":"Thread deleted successfully"},"401":{"description":"Unauthorized - missing access token"},"403":{"description":"Forbidden - invalid secret key"},"500":{"description":"Internal server error"},"503":{"description":"Memory service temporarily unavailable"}}},"servers":[{"url":"/"}]},"/v1/api/memory/threads/delete-multiple":{"post":{"tags":["Memory"],"description":"Delete multiple threads by their IDs (only threads owned by the user)","requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"threadIds":{"type":"array","items":{"type":"string"},"description":"Array of thread IDs to delete"}},"required":["threadIds"]}}}},"responses":{"200":{"description":"Threads deleted successfully"},"400":{"description":"Invalid request body"},"401":{"description":"Unauthorized - missing or invalid access token"},"500":{"description":"Internal server error"},"503":{"description":"Memory service temporarily unavailable"}}},"servers":[{"url":"/"}]},"/v1/api/memory/threads/bot/{botId}":{"delete":{"tags":["Memory"],"description":"Delete all threads associated with a specific bot for the current user","responses":{"200":{"description":"Threads deleted successfully"},"401":{"description":"Unauthorized - missing or invalid access token"},"409":{"description":"Database constraint violation"},"500":{"description":"Internal server error"}}},"servers":[{"url":"/"}]},"/v1/api/memory/threads/data-room/{dataRoomId}":{"delete":{"tags":["Memory"],"description":"Delete all threads associated with a specific data room for the current user","responses":{"200":{"description":"Threads deleted successfully"},"401":{"description":"Unauthorized - missing or invalid access token"},"409":{"description":"Database constraint violation"},"500":{"description":"Internal server error"}}},"servers":[{"url":"/"}]},"/healthz":{"get":{"tags":["System"],"description":"Health check endpoint to verify service availability","x-auth-bypass":true,"responses":{"200":{"description":"Service is healthy"}}},"servers":[{"url":"/"}]},"/v1/api/agents/tools":{"get":{"tags":["Agents"],"description":"Retrieve list of all available tools for agents","responses":{"200":{"description":"Tools retrieved successfully"},"401":{"description":"Unauthorized - missing or invalid access token"},"500":{"description":"Internal server error"}}},"servers":[{"url":"/"}]},"/v1/api/agents/follow-up/{threadId}":{"get":{"tags":["Agents"],"description":"Retrieve follow-up questions based on a specific thread ID","parameters":[{"name":"threadId","in":"path","required":true,"schema":{"type":"string"},"description":"The ID of the thread to analyze"}],"responses":{"200":{"description":"Follow-up questions generated successfully","content":{"application/json":{"schema":{"type":"object","properties":{"questions":{"type":"array","items":{"type":"string"}}}}}}},"401":{"description":"Unauthorized - missing or invalid access token"},"404":{"description":"Thread not found"},"500":{"description":"Internal server error"}}},"servers":[{"url":"/"}]},"/v1/api/memory/threads/export":{"post":{"tags":["Memory"],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"convo_id":{"type":"string"},"file_type":{"type":"string"},"time_zone":{"type":"number"},"title":{"type":"string"}},"required":["convo_id","file_type","time_zone"]}}}},"responses":{"200":{"description":"PDF generated, uploaded, and session created successfully","content":{"application/json":{"schema":{"type":"object","properties":{"fileUrl":{"type":"string","description":"Signed media session URL for the PDF"},"filename":{"type":"string","description":"Filename of the generated PDF"}},"required":["fileUrl","filename"]},"examples":{"success":{"value":{"fileUrl":"https://media-server.local/media/<sessionId>","filename":"Exported_Thread.pdf"}}}}}},"400":{"description":"Thread not found or empty","content":{"application/json":{"schema":{"type":"object","properties":{"code":{"type":"number"},"key":{"type":"string"},"body":{"type":"string"}},"required":["code","key","body"]},"examples":{"threadNotFound":{"value":{"code":400,"key":"agentic-thread-not-found","body":"Oops! Looks like the conversation is no longer available or empty"}}}}}},"401":{"description":"Unauthorized","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}},"required":["error"]},"examples":{"unauthorized":{"value":{"error":"Unauthorized"}}}}}},"500":{"description":"Internal server error (PDF generation, upload, or session creation failed)","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}},"required":["error"]},"examples":{"uploadFailed":{"value":{"error":"Failed to upload PDF"}},"sessionFailed":{"value":{"error":"Failed to create media session"}},"generic":{"value":{"error":"Internal server error"}}}}}}}},"servers":[{"url":"/"}]},"/v1/api/memory/messages/export":{"post":{"tags":["Memory"],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"message_id":{"type":"string"},"file_type":{"type":"string"},"time_zone":{"type":"number"},"bot_id":{"type":"string"}},"required":["message_id","file_type","time_zone"]}}}}},"servers":[{"url":"/"}]},"/v1/api/media/snapshots":{"post":{"tags":["Media"],"summary":"Upload a chart/diagram snapshot PNG for export embedding","description":"Stores a client-rendered chart/diagram PNG under its tool-allocated snapshot key so PDF/DOCX exports can embed it. The storage tenant is derived from the authenticated acting organization.","requestBody":{"required":true,"content":{"multipart/form-data":{"schema":{"type":"object","properties":{"file":{"type":"string","format":"binary","description":"PNG snapshot (max 10 MB)"},"key":{"type":"string","description":"Snapshot key: botticelli/(chart|diagram)-snapshot/<toolCallId>"}},"required":["file","key"]}}}},"responses":{"200":{"description":"Snapshot stored","content":{"application/json":{"schema":{"type":"object","properties":{"key":{"type":"string"}},"required":["key"]}}}},"400":{"description":"Missing/invalid field, invalid snapshot key, or non-PNG content"},"401":{"description":"Missing or unresolved authentication context"},"413":{"description":"Snapshot exceeds the 10 MB limit"},"502":{"description":"Media-server upload failed"}}},"servers":[{"url":"/"}]},"/v1/api/memory/messages/metadata":{"put":{"tags":["Memory"],"description":"Update metadata for multiple messages in bulk","requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"messages":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","description":"The message ID to update"},"metadata":{"type":"object","description":"The metadata to update for the message"}},"required":["id"]},"description":"Array of messages with their IDs and metadata to update"}},"required":["messages"]}}}},"responses":{"200":{"description":"Messages metadata updated successfully"},"400":{"description":"Invalid request body"},"401":{"description":"Unauthorized - missing or invalid access token"},"500":{"description":"Internal server error"},"503":{"description":"Memory service temporarily unavailable"}}},"servers":[{"url":"/"}]},"/v1/api/run-workflow":{"post":{"tags":["Workflows"],"description":"Execute a workflow synchronously and return the result","requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"workflowName":{"type":"string","description":"Name of the workflow to execute"},"workflowId":{"type":"string","description":"Optional workflow ID"},"nodes":{"type":"array","items":{"type":"object"},"description":"Workflow nodes"},"edges":{"type":"array","items":{"type":"object"},"description":"Workflow edges"},"inputData":{"type":"object","description":"Input data for the workflow"}},"required":["workflowName"]}}}},"responses":{"200":{"description":"Workflow executed successfully"},"400":{"description":"Invalid request body"},"401":{"description":"Unauthorized - missing or invalid access token"},"500":{"description":"Workflow execution failed"}}},"servers":[{"url":"/"}]},"/v1/api/workflows/send-event":{"post":{"tags":["Workflows"],"description":"Send an event to resume or interact with running workflows","requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"event":{"type":"string","description":"Event type to send to workflows"},"resume_data":{"type":"object","additionalProperties":true,"description":"Data to resume workflow with"}},"required":["event","resume_data"]}}}},"responses":{"200":{"description":"Workflow resumed successfully"},"400":{"description":"Invalid request body"},"401":{"description":"Unauthorized - missing or invalid access token"},"500":{"description":"Internal server error"}}},"servers":[{"url":"/"}]},"/v1/api/agentic/workflows/save":{"post":{"tags":["Workflows"],"description":"Delete an attachment from an agentic workflow","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"workflowId":{"type":"string","description":"ID of the workflow"},"attachmentId":{"type":"string","description":"ID of the attachment to delete"}},"required":["workflowId","attachmentId"]}}}},"responses":{"200":{"description":"Attachment deleted successfully"},"400":{"description":"Invalid request body"},"401":{"description":"Unauthorized - missing or invalid access token"},"500":{"description":"Internal server error"}}},"servers":[{"url":"/"}]},"/v1/api/agentic/workflows/run":{"post":{"tags":["Workflows"],"description":"Execute an agentic workflow asynchronously","requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"workflowId":{"type":"string","description":"ID of the workflow to execute"},"workflowInput":{"type":"object","additionalProperties":true,"description":"Input data for the workflow"}},"required":["workflowId","workflowInput"]}}}},"responses":{"200":{"description":"Workflow execution started successfully"},"400":{"description":"Invalid request body"},"401":{"description":"Unauthorized - missing or invalid access token"},"500":{"description":"Internal server error"}}},"servers":[{"url":"/"}]},"/v1/api/agentic/workflows/get-status/run-id/{artificialRunId}/last-id/{lastId}":{"get":{"tags":["Workflows"],"description":"Poll for workflow execution status updates using Redis stream","responses":{"200":{"description":"Workflow status retrieved successfully"},"401":{"description":"Unauthorized - missing or invalid access token"},"500":{"description":"Internal server error"},"503":{"description":"Redis service temporarily unavailable"}}},"servers":[{"url":"/"}]},"/v1/api/agentic/workflows/get-workflows":{"get":{"tags":["Workflows"],"description":"Retrieve list of all agentic workflows for the authenticated user","responses":{"200":{"description":"Workflows retrieved successfully"},"401":{"description":"Unauthorized - missing or invalid access token"},"500":{"description":"Internal server error"}}},"servers":[{"url":"/"}]},"/v1/api/agentic/workflows/get-results/workflow/{workflowId}":{"get":{"tags":["Workflows"],"description":"Retrieve execution results for a specific workflow","responses":{"200":{"description":"Workflow results retrieved successfully"},"401":{"description":"Unauthorized - missing or invalid access token"},"500":{"description":"Internal server error"}}},"servers":[{"url":"/"}]},"/v1/api/agentic/workflows/delete":{"post":{"tags":["Workflows"],"description":"Delete multiple agentic workflows by their IDs","requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"workflowIds":{"type":"array","items":{"type":"string"},"description":"Array of workflow IDs to delete"}},"required":["workflowIds"]}}}},"responses":{"200":{"description":"Workflows deleted successfully"},"401":{"description":"Unauthorized - missing or invalid access token"},"500":{"description":"Internal server error"}}},"servers":[{"url":"/"}]},"/v1/api/agents/{agentId}/stream":{"post":{"deprecated":true,"tags":["Agents"],"summary":"Stream agent chat (deprecated)","description":"Deprecated event-based SSE stream. Emits named SSE events (`event: <type>\\ndata: <json>\\n\\n`). This endpoint is frozen — migrate to POST /v2/api/agents/:agentId/stream (AI SDK v6 UIMessage format, suspend/resume, tool-call approval).","parameters":[{"name":"agentId","in":"path","required":true,"description":"The ID of the agent to chat with","schema":{"type":"string"}},{"name":"x-tool-ids","in":"header","required":false,"description":"Comma-separated list of tool IDs to enable for this request. Used by non-Blocky clients (e.g., Eddy) that do not send x-blockbrain-data-room-id.","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"messages":{"type":"array","items":{"type":"object"},"description":"Conversation messages"},"threadId":{"type":"string","description":"Thread ID for memory persistence"},"resourceId":{"type":"string","description":"Resource (user) ID associated with the thread"}},"required":["messages"]}}}},"responses":{"200":{"description":"Named SSE event stream (`event: <type>\\ndata: <json>\\n\\n`)","content":{"text/event-stream":{"schema":{"type":"string"}}}},"400":{"description":"Invalid request body"},"401":{"description":"Unauthorized"},"404":{"description":"Agent not found"},"429":{"description":"Usage limit reached for the current period","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["usage_limit_reached"]},"message":{"type":"string"},"used":{"type":"number"},"limit":{"type":"number"},"timeframe":{"type":"string","enum":["monthly","weekly","daily"]},"periodResetsAt":{"type":"string","format":"date-time"}},"required":["error","message","used","limit","timeframe","periodResetsAt"]}}}}}},"servers":[{"url":"/"}]},"/v2/api/agents/{agentId}/stream":{"post":{"tags":["Agents"],"summary":"Stream agent chat","description":"Send messages to an agent and stream the response using AI SDK v6 UIMessage format. Supports suspend/resume for tool-call approval (human-in-the-loop). Thread/memory association is done via the `memory` field. For the deprecated event-based SSE format, use POST /v1/api/agents/:agentId/stream.","parameters":[{"name":"agentId","in":"path","required":true,"description":"The ID of the agent to chat with","schema":{"type":"string"}},{"name":"x-tool-ids","in":"header","required":false,"description":"Comma-separated list of tool IDs to enable for this request. Used by non-Blocky clients (e.g., Eddy) that do not send x-blockbrain-data-room-id. When present, these tools are added to the agent's available tool set.","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["messages"],"properties":{"messages":{"type":"array","description":"Array of UIMessages (AI SDK v6 format).","items":{"type":"object"}},"resumeData":{"type":"object","description":"Resume payload for a suspended tool-call approval."},"runId":{"type":"string","description":"Run ID required when resuming a suspended execution."},"trigger":{"type":"string","enum":["submit-message","regenerate-message"],"description":"Client action trigger; regenerate re-runs the last assistant message."},"memory":{"type":"object","description":"Memory configuration for thread persistence. Pass `thread` (thread ID or object with `id`) and `resource` (user/resource ID) to associate this run with a stored conversation thread. Without this field, messages are not persisted.","properties":{"thread":{"description":"Thread identifier. Either a plain ID string or an object containing `id`.","anyOf":[{"type":"string","description":"Thread ID string"},{"type":"object","properties":{"id":{"type":"string"}},"required":["id"],"additionalProperties":true,"description":"Thread object (at minimum `{ id: string }`)"}]},"resource":{"type":"string","description":"Resource (user) ID associated with this thread."},"options":{"type":"object","additionalProperties":{},"description":"Advanced memory configuration options (e.g. semantic search settings)."},"readOnly":{"type":"boolean","description":"When true, memory is read but not written during this run."}},"required":["thread","resource"],"additionalProperties":false},"instructions":{"description":"Additional system instructions to inject for this run.","anyOf":[{"type":"string"},{"type":"array","items":{"type":"string"}}]},"maxSteps":{"type":"number","description":"Maximum number of agentic tool-call steps before the run is halted."},"activeTools":{"type":"array","items":{"type":"string"},"description":"Allowlist of tool names the agent may use in this run."},"externalTools":{"type":"array","description":"External tool definitions for relay execution. Tools defined here are presented to the model as native tools. The suspend/relay is honored only by the WebComponent Agent: when its model calls one, the stream suspends and emits a data-tool-call-suspended event, the client executes the tool locally and resumes with resumeData + runId. The resume request must re-send this externalTools array (the relay tool is rebuilt per request). For other agents the tools are exposed to the model but calls are not executed or relayed.","items":{"type":"object","required":["name","description","parameters"],"properties":{"name":{"type":"string","description":"Unique tool name"},"description":{"type":"string","description":"What the tool does (shown to the model)"},"parameters":{"type":"object","description":"JSON Schema describing the tool input"}}}},"toolChoice":{"description":"How the agent selects tools.","anyOf":[{"type":"string","enum":["auto","none","required"]},{"type":"object","properties":{"type":{"type":"string","enum":["tool"]},"toolName":{"type":"string"}},"required":["type","toolName"],"additionalProperties":false}]},"requireToolApproval":{"type":"boolean","description":"When true, tool calls are suspended and a `data-tool-call-approval` event is emitted. Resume with `resumeData` + `runId`."},"providerOptions":{"type":"object","description":"Provider-specific options (e.g. Anthropic thinking budget).","properties":{"anthropic":{"type":"object","additionalProperties":{}},"google":{"type":"object","additionalProperties":{}},"openai":{"type":"object","additionalProperties":{}}},"additionalProperties":false},"tracingOptions":{"type":"object","description":"OpenTelemetry tracing metadata for this run.","properties":{"metadata":{"type":"object","additionalProperties":{}},"traceId":{"type":"string"},"parentSpanId":{"type":"string"}},"additionalProperties":false},"output":{"description":"Expected output schema (structured output)."}}}}}},"responses":{"200":{"description":"Streaming response from the agent","content":{"text/event-stream":{"schema":{"type":"string","description":"AI SDK v6 UIMessage chunk SSE stream"}}}},"400":{"description":"Bad request — invalid input"},"404":{"description":"Agent not found"},"429":{"description":"Usage limit reached for the current period","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","enum":["usage_limit_reached"]},"message":{"type":"string"},"used":{"type":"number"},"limit":{"type":"number"},"timeframe":{"type":"string","enum":["monthly","weekly","daily"]},"periodResetsAt":{"type":"string","format":"date-time"}},"required":["error","message","used","limit","timeframe","periodResetsAt"]}}}}}},"servers":[{"url":"/"}]},"/v2/api/audio/transcriptions":{"post":{"tags":["Audio"],"summary":"Transcribe audio (speech-to-text)","description":"OpenAI-compatible /v1/audio/transcriptions proxy. Accepts a multipart audio file plus a LiteLLM model name; returns OpenAI-shaped JSON `{ text }`.","requestBody":{"required":true,"content":{"multipart/form-data":{"schema":{"type":"object","required":["file","model"],"properties":{"file":{"type":"string","format":"binary"},"model":{"type":"string","description":"LiteLLM STT model id (e.g. whisper-1, azure/whisper)"},"language":{"type":"string","description":"ISO-639 hint"},"prompt":{"type":"string","description":"Biasing prompt for Whisper-class models"},"temperature":{"type":"number","description":"0.0–1.0"}}}}}},"responses":{"200":{"description":"OpenAI-compatible transcription response","content":{"application/json":{"schema":{"type":"object","properties":{"text":{"type":"string"}},"required":["text"]}}}},"400":{"description":"Bad request — missing file/model or unsupported filetype"},"413":{"description":"Audio exceeds the 25 MB cap"},"502":{"description":"LiteLLM upstream failure"}}},"servers":[{"url":"/"}]},"/v2/api/audio/speech":{"post":{"tags":["Audio"],"summary":"Synthesize speech (text-to-speech)","description":"OpenAI-compatible /v1/audio/speech proxy. JSON in, audio bytes out. The `response_format` field controls the audio container; the response Content-Type is set to match (defaults to audio/mpeg for mp3).","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["model","input"],"properties":{"model":{"type":"string","description":"LiteLLM TTS model id (e.g. tts-1, azure/tts-1-hd)"},"input":{"type":"string","description":"Text to synthesize. Capped at 4000 chars."},"voice":{"type":"string","description":"Voice id required by OpenAI-style models"},"response_format":{"type":"string","enum":["mp3","opus","aac","flac","wav","pcm"]},"speed":{"type":"number","description":"0.25–4.0"}}}}}},"responses":{"200":{"description":"Streamed audio bytes","content":{"audio/mpeg":{"schema":{"type":"string","format":"binary"}}}},"400":{"description":"Bad request — missing/invalid input"},"502":{"description":"LiteLLM upstream failure"}}},"servers":[{"url":"/"}]},"/v2/api/audio/models":{"get":{"tags":["Audio"],"summary":"List audio (STT/TTS) models","description":"Returns LiteLLM models filtered by audio capability. Use ?mode=audio_transcription or ?mode=audio_speech.","parameters":[{"name":"mode","in":"query","required":false,"schema":{"type":"string","enum":["audio_transcription","audio_speech"]},"description":"Filter to a specific audio mode. When omitted, both transcription and speech models are returned."}],"responses":{"200":{"description":"Filtered model list","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"mode":{"type":"string"},"provider":{"type":"string"}}}},"total":{"type":"number"}}}}}},"400":{"description":"Invalid mode parameter"}}},"servers":[{"url":"/"}]},"/v2/api/threads":{"get":{"tags":["DynamicChat"],"summary":"List chat threads","description":"List the current user's threads for the agent-first chat product.","responses":{"200":{"description":"Thread list","content":{"application/json":{"schema":{"type":"array","items":{"type":"object"}}}}},"401":{"description":"Unauthorized"},"503":{"description":"Memory service temporarily unavailable"}}},"post":{"tags":["DynamicChat"],"summary":"Create a chat thread","description":"Create a new thread for the agent-first chat product. `agentId` is a workspace agent UUID; omit to fall back to the hardcoded default.","requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"agentId":{"type":"string","format":"uuid","description":"Workspace agent UUID. When set, the stream resolves prompt + model from workspace at request time. Omit to use hardcoded defaults."},"title":{"type":"string","description":"Optional human-readable thread title."}}}}}},"responses":{"201":{"description":"Thread created"},"401":{"description":"Unauthorized"},"503":{"description":"Memory service temporarily unavailable"}}},"servers":[{"url":"/"}]},"/v2/api/threads/{threadId}":{"get":{"tags":["DynamicChat"],"summary":"Get a chat thread","parameters":[{"name":"threadId","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Thread"},"401":{"description":"Unauthorized"},"404":{"description":"Thread not found"},"503":{"description":"Memory service temporarily unavailable"}}},"delete":{"tags":["DynamicChat"],"summary":"Delete a chat thread","parameters":[{"name":"threadId","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"204":{"description":"Thread deleted (or absent — response is idempotent)."},"401":{"description":"Unauthorized"},"503":{"description":"Memory service temporarily unavailable"}}},"servers":[{"url":"/"}]},"/v2/api/threads/{threadId}/todos":{"get":{"tags":["DynamicChat"],"summary":"Get thread todo list","parameters":[{"name":"threadId","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Todo list","content":{"application/json":{"schema":{"type":"object","properties":{"todos":{"type":"array","items":{"type":"object"}},"updatedAt":{"type":"string","nullable":true}}}}}},"401":{"description":"Unauthorized"},"404":{"description":"Thread not found or feature not enabled"},"500":{"description":"Internal error"},"503":{"description":"Memory service unavailable"}}},"servers":[{"url":"/"}]},"/v2/api/threads/{threadId}/messages":{"get":{"tags":["DynamicChat"],"summary":"Get a thread message history","description":"Returns the last 50 messages of the thread in AI SDK v6 UIMessage format.","parameters":[{"name":"threadId","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Thread message history","content":{"application/json":{"schema":{"type":"array","description":"AI SDK v6 UIMessage objects","items":{"type":"object"}}}}},"401":{"description":"Unauthorized"},"404":{"description":"Thread not found or not owned by caller"},"503":{"description":"Memory service temporarily unavailable"}}},"post":{"tags":["DynamicChat"],"summary":"Send a message and stream the agent response","description":"Streams the dynamic chat agent response as an AI SDK v6 UIMessage SSE stream. Thread ID comes from the path; resource (user) ID is derived from the JWT.","parameters":[{"name":"threadId","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["messages"],"properties":{"messages":{"type":"array","description":"Array of UIMessages (AI SDK v6 format).","items":{"type":"object"}}}}}}},"responses":{"200":{"description":"Streaming response","content":{"text/event-stream":{"schema":{"type":"string","description":"AI SDK v6 UIMessage chunk SSE stream"}}}},"400":{"description":"Bad request — invalid body"},"401":{"description":"Unauthorized"},"404":{"description":"Thread not found or not owned by caller"},"500":{"description":"Internal error"}}},"servers":[{"url":"/"}]},"/v2/api/threads/{threadId}/agent":{"post":{"tags":["DynamicChat"],"summary":"Swap the workspace agent pinned to a thread","description":"Upserts `current_agent_id` on the thread's `workspace.thread_configs` row. Next turn on the thread streams using the new agent's prompt + model.","parameters":[{"name":"threadId","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"agentId":{"type":"string","nullable":true,"format":"uuid","description":"Workspace agent UUID, or `null` to unpin and fall back to defaults."}}}}}},"responses":{"200":{"description":"Thread updated"},"400":{"description":"Invalid body"},"401":{"description":"Unauthorized"},"404":{"description":"Thread not found or not owned by caller"},"503":{"description":"Memory service temporarily unavailable"}}},"servers":[{"url":"/"}]},"/v1/api/supervisors/available-agents":{"get":{"tags":["Custom Supervisors"],"description":"List agent IDs available as sub-agents for custom supervisors","responses":{"200":{"description":"List of available agent IDs with display names"}}},"servers":[{"url":"/"}]},"/v1/api/supervisors":{"post":{"tags":["Custom Supervisors"],"description":"Create a new custom supervisor configuration","x-required-roles":["kb:admin","kb:superadmin"],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string","description":"Display name for the supervisor"},"instructions":{"type":"string","description":"System prompt for the supervising LLM"},"model":{"type":"string","description":"LiteLLM model name (optional, uses default when omitted)"},"subAgentIds":{"type":"array","items":{"type":"string"},"description":"Agent IDs the supervisor is allowed to delegate to"}},"required":["name","instructions","subAgentIds"]}}}},"responses":{"201":{"description":"Custom supervisor created successfully"},"400":{"description":"Invalid request body"},"401":{"description":"Unauthorized"}}},"get":{"tags":["Custom Supervisors"],"description":"List all custom supervisors for the authenticated organisation","x-required-roles":["kb:admin","kb:superadmin"],"responses":{"200":{"description":"List of custom supervisors"},"401":{"description":"Unauthorized"}}},"servers":[{"url":"/"}]},"/v1/api/supervisors/{id}":{"get":{"tags":["Custom Supervisors"],"description":"Get a single custom supervisor by ID","x-required-roles":["kb:admin","kb:superadmin"],"responses":{"200":{"description":"Custom supervisor details"},"401":{"description":"Unauthorized"},"404":{"description":"Not found"}}},"put":{"tags":["Custom Supervisors"],"description":"Update an existing custom supervisor configuration","x-required-roles":["kb:admin","kb:superadmin"],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string"},"instructions":{"type":"string"},"model":{"type":"string"},"subAgentIds":{"type":"array","items":{"type":"string"}}}}}}},"responses":{"200":{"description":"Updated custom supervisor"},"400":{"description":"Invalid request body"},"401":{"description":"Unauthorized"},"404":{"description":"Not found"}}},"delete":{"tags":["Custom Supervisors"],"description":"Delete a custom supervisor configuration","x-required-roles":["kb:admin","kb:superadmin"],"responses":{"200":{"description":"Deleted successfully"},"401":{"description":"Unauthorized"},"404":{"description":"Not found"}}},"servers":[{"url":"/"}]},"/v1/api/scheduled-messages":{"post":{"tags":["Scheduled Messages"],"description":"Create a new scheduled message for automated chat execution","x-required-roles":["kb:admin","kb:superadmin"],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"threadId":{"type":"string","description":"Thread ID to send messages to"},"agentId":{"type":"string","description":"Agent ID to use for processing"},"message":{"type":"string","description":"Message content to send","maxLength":10000},"intervalPreset":{"type":"string","description":"Predefined interval or \"custom\" for custom cron","enum":["every_15_minutes","every_30_minutes","every_hour","every_2_hours","every_6_hours","every_12_hours","daily_9am","daily_noon","daily_6pm","weekly_monday_9am","custom"]},"customCron":{"type":"string","description":"Custom cron expression (required when intervalPreset is \"custom\")"},"metadata":{"type":"object","description":"Additional metadata (botId, dataRoomId, networkId, displayName)"}},"required":["threadId","agentId","message","intervalPreset"]}}}},"responses":{"201":{"description":"Scheduled message created successfully"},"400":{"description":"Invalid request body"},"401":{"description":"Unauthorized"}}},"get":{"tags":["Scheduled Messages"],"description":"List scheduled messages for the current user or a specific thread","x-required-roles":["kb:admin","kb:superadmin"],"parameters":[{"name":"threadId","in":"query","description":"Filter by thread ID","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"List of scheduled messages"},"401":{"description":"Unauthorized"}}},"servers":[{"url":"/"}]},"/v1/api/scheduled-messages/{id}":{"get":{"tags":["Scheduled Messages"],"description":"Get a specific scheduled message by ID","x-required-roles":["kb:admin","kb:superadmin"],"parameters":[{"name":"id","in":"path","description":"Scheduled message ID","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Scheduled message details"},"401":{"description":"Unauthorized"},"404":{"description":"Scheduled message not found"}}},"put":{"tags":["Scheduled Messages"],"description":"Update a scheduled message","x-required-roles":["kb:admin","kb:superadmin"],"parameters":[{"name":"id","in":"path","description":"Scheduled message ID","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","description":"Message content"},"intervalPreset":{"type":"string","description":"Interval preset"},"customCron":{"type":"string","description":"Custom cron expression"},"isActive":{"type":"boolean","description":"Enable/disable the scheduled message"}}}}}},"responses":{"200":{"description":"Scheduled message updated successfully"},"400":{"description":"Invalid request body"},"401":{"description":"Unauthorized"},"404":{"description":"Scheduled message not found"}}},"delete":{"tags":["Scheduled Messages"],"description":"Delete a scheduled message","x-required-roles":["kb:admin","kb:superadmin"],"parameters":[{"name":"id","in":"path","description":"Scheduled message ID","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Scheduled message deleted successfully"},"401":{"description":"Unauthorized"},"404":{"description":"Scheduled message not found"}}},"servers":[{"url":"/"}]},"/v1/api/scheduled-messages/{id}/toggle":{"post":{"tags":["Scheduled Messages"],"description":"Toggle the active state of a scheduled message","x-required-roles":["kb:admin","kb:superadmin"],"parameters":[{"name":"id","in":"path","description":"Scheduled message ID","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Scheduled message toggled successfully"},"401":{"description":"Unauthorized"},"404":{"description":"Scheduled message not found"}}},"servers":[{"url":"/"}]},"/docs":{"get":{"tags":["System"],"description":"Interactive API documentation (Scalar)","x-auth-bypass":true,"responses":{"200":{"description":"API documentation page"}}}},"/changelog":{"get":{"tags":["System"],"description":"Structured changelog for this service. Returns only entries that directly affect @botticelli/mastra-operators, grouped by release and change type.","requestBody":{"query":{"limit":{"type":"number","description":"Maximum number of releases to return (default: all)"}}},"responses":{"200":{"description":"Changelog as structured JSON","content":{"application/json":{"schema":{"type":"object","properties":{"package":{"type":"string"},"releases":{"type":"array","items":{"type":"object","properties":{"date":{"type":"string","format":"date"},"version":{"type":"string"},"summary":{"type":"string"},"breaking":{"type":"array","items":{"type":"string"}},"new_capabilities":{"type":"array","items":{"type":"string"}},"changes":{"type":"array","items":{"type":"string"}},"fixes":{"type":"array","items":{"type":"string"}},"removed":{"type":"array","items":{"type":"string"}}}}}}}}}},"404":{"description":"Changelog has not been generated yet"}}}},"/llms.txt":{"get":{"tags":["System"],"description":"LLM-friendly API documentation in llms.txt format (https://llmstxt.org). Lists all public endpoints grouped by tag with parameters and response shapes.","x-auth-bypass":true,"responses":{"200":{"description":"llms.txt document"},"502":{"description":"Could not fetch OpenAPI spec"}}}},"/metrics":{"get":{"tags":["System"],"description":"Prometheus metrics exposition (retrieval SLI counters/histograms). Unauthenticated.","x-auth-bypass":true,"responses":{"200":{"description":"Prometheus text exposition format","content":{"text/plain":{"schema":{"type":"string"}}}}}}},"/api/agents/{agentId}/stream":{"post":{"tags":["Agents","Legacy"],"deprecated":true,"summary":"Stream agent response (Legacy AI SDK v1)","description":"Streaming endpoint using AI SDK v1 data-stream wire format. Requests are immediately returned as a stream and internally proxied via the early-stream service to /api/agents/:agentId/stream-legacy. Migrate to POST /v2/api/agents/:agentId/stream (AI SDK v6 UIMessage format).","parameters":[{"name":"agentId","in":"path","required":true,"description":"Unique identifier for the agent","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"messages":{"anyOf":[{"type":"array"},{"type":"string"}],"description":"Conversation messages in AI SDK v1 format."},"threadId":{"type":"string","description":"Thread ID for memory persistence. If omitted, messages are not saved."},"resourceId":{"type":"string","description":"Resource (user) ID associated with the thread. Falls back to threadId if not provided."},"runId":{"type":"string","description":"Optional run ID for tracing."},"instructions":{"anyOf":[{"type":"string"},{"type":"array","items":{"type":"string"}}],"description":"Additional system instructions to prepend."},"maxSteps":{"type":"number","description":"Maximum number of agentic steps."}},"required":["messages"],"additionalProperties":true}}}},"responses":{"200":{"description":"AI SDK v1 data-stream (text/plain). Prefixed with early status tokens (\"preparing_request\", \"streaming\") emitted by the early-stream proxy.","content":{"text/plain":{"schema":{"type":"string"}}}},"401":{"description":"Unauthorized - missing or invalid access token"},"404":{"description":"Agent not found"},"500":{"description":"Internal server error"}}}},"/api/agents/{agentId}/stream-legacy":{"post":{"tags":["Agents","Legacy"],"deprecated":true,"summary":"Stream agent response — legacy internal target","description":"Internal target of the early-stream proxy rewrite — do not call directly. Use POST /api/agents/:agentId/stream (which proxies here via the early-stream service) or migrate to POST /v2/api/agents/:agentId/stream.","parameters":[{"name":"agentId","in":"path","required":true,"description":"Unique identifier for the agent","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"messages":{"anyOf":[{"type":"array"},{"type":"string"}],"description":"Conversation messages in AI SDK v1 format."},"threadId":{"type":"string","description":"Thread ID for memory persistence. If omitted, messages are not saved."},"resourceId":{"type":"string","description":"Resource (user) ID associated with the thread. Falls back to threadId if not provided."},"runId":{"type":"string","description":"Optional run ID for tracing."},"instructions":{"anyOf":[{"type":"string"},{"type":"array","items":{"type":"string"}}],"description":"Additional system instructions to prepend."},"maxSteps":{"type":"number","description":"Maximum number of agentic steps."}},"required":["messages"],"additionalProperties":true}}}},"responses":{"200":{"description":"AI SDK v1 data-stream (text/plain). Prefixed with early status tokens (\"preparing_request\", \"streaming\") emitted by the early-stream proxy.","content":{"text/plain":{"schema":{"type":"string"}}}},"401":{"description":"Unauthorized - missing or invalid access token"},"404":{"description":"Agent not found"},"500":{"description":"Internal server error"}}}}},"servers":[{"url":"/api"}]}