{ "openapi": "3.1.0", "info": { "title": "Speaking Meeting Bot API", "description": "API for deploying AI-powered speaking agents in video meetings. Combines MeetingBaas for meeting connectivity with Pipecat for voice AI processing.", "version": "0.1.0" }, "paths": { "/bots": { "post": { "tags": [ "bots" ], "summary": "Join Meeting", "description": "Create and deploy a speaking bot in a meeting.\n\nLaunches an AI-powered bot that joins a video meeting through MeetingBaas\nand processes audio using Pipecat's voice AI framework.", "operationId": "join_meeting_bots_post", "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/BotRequest" } } }, "required": true }, "responses": { "201": { "description": "Bot successfully created and joined the meeting", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/JoinResponse" } } } }, "400": { "description": "Bad request - Missing required fields or invalid data" }, "500": { "description": "Server error - Failed to create bot through MeetingBaas API" }, "422": { "description": "Validation Error", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/HTTPValidationError" } } } } } } }, "/bots/{bot_id}": { "delete": { "tags": [ "bots" ], "summary": "Leave Bot", "description": "Remove a bot from a meeting by its ID.\n\nThis will:\n1. Call the MeetingBaas API to make the bot leave\n2. Close WebSocket connections if they exist\n3. Terminate the associated Pipecat process", "operationId": "leave_bot_bots__bot_id__delete", "parameters": [ { "name": "bot_id", "in": "path", "required": true, "schema": { "type": "string", "title": "Bot Id" } } ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/LeaveBotRequest" } } } }, "responses": { "200": { "description": "Bot successfully removed from meeting", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/LeaveResponse" } } } }, "400": { "description": "Bad request - Missing required fields or identifiers" }, "404": { "description": "Bot not found - No bot with the specified ID" }, "500": { "description": "Server error - Failed to remove bot from MeetingBaas API" }, "422": { "description": "Validation Error", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/HTTPValidationError" } } } } } } }, "/personas/generate-image": { "post": { "tags": [ "personas" ], "summary": "Generate Persona Image", "description": "Generate an image for a persona using Replicate.", "operationId": "generate_persona_image_personas_generate_image_post", "requestBody": { "required": true, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/PersonaImageRequest" } } } }, "responses": { "201": { "description": "Image successfully generated", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/PersonaImageResponse" } } } }, "400": { "description": "Invalid request data" }, "422": { "description": "Validation Error", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/HTTPValidationError" } } } } } } }, "/bots/{bot_id}/messages": { "post": { "tags": [ "bots" ], "summary": "Send Owner Message", "description": "Have the bot relay a message from its owner to the meeting.\n\nFor things that come up while the owner is away: \"tell them I'll join at\nhalf past\", \"we can go with option B\". The bot says it in its own words,\nbriefly, and the text appears in the transcript as its turn. Only the API\nkey that created the bot may use this.", "operationId": "send_owner_message_bots__bot_id__messages_post", "parameters": [ { "name": "bot_id", "in": "path", "required": true, "schema": { "type": "string", "title": "Bot Id" } } ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/OwnerMessageRequest" } } } }, "responses": { "202": { "description": "Queued; the bot relays it within a second or two", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/AcceptedResponse" } } } }, "404": { "description": "No live bot with that ID" }, "422": { "description": "Validation Error", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/HTTPValidationError" } } } } } } }, "/bots/{bot_id}/escalations": { "get": { "tags": [ "bots" ], "summary": "List Escalations", "description": "The decisions the bot has handed back to its owner during this call.\n\nEach entry carries the question, its category, who asked, and the owner's\nanswer once one was posted. The same list is in the call-end event. Only\nthe API key that created the bot may read it.", "operationId": "list_escalations_bots__bot_id__escalations_get", "parameters": [ { "name": "bot_id", "in": "path", "required": true, "schema": { "type": "string", "title": "Bot Id" } } ], "responses": { "200": { "description": "Successful Response", "content": { "application/json": { "schema": { "type": "array", "items": { "$ref": "#/components/schemas/Escalation" }, "title": "Response List Escalations Bots Bot Id Escalations Get" } } } }, "404": { "description": "No live bot with that ID" }, "422": { "description": "Validation Error", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/HTTPValidationError" } } } } } } }, "/bots/{bot_id}/escalations/{escalation_id}/response": { "post": { "tags": [ "bots" ], "summary": "Answer Escalation", "description": "Answer an escalation the bot raised.\n\nThe bot tells the participants the owner's answer, word for word in\nsubstance, and the escalation is marked answered in the briefing. An\nescalation that is never answered stays open and is reported as\nunresolved; the bot never assumes approval. Only the API key that created\nthe bot may answer.", "operationId": "answer_escalation_bots__bot_id__escalations__escalation_id__response_post", "parameters": [ { "name": "bot_id", "in": "path", "required": true, "schema": { "type": "string", "title": "Bot Id" } }, { "name": "escalation_id", "in": "path", "required": true, "schema": { "type": "string", "title": "Escalation Id" } } ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/EscalationResponseRequest" } } } }, "responses": { "202": { "description": "Queued; the bot relays the answer to the meeting", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/AcceptedResponse" } } } }, "404": { "description": "No live bot, or no such escalation" }, "422": { "description": "Validation Error", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/HTTPValidationError" } } } } } } }, "/bots/{bot_id}/usage": { "get": { "tags": [ "bots" ], "summary": "Get Bot Usage", "description": "What the bot has consumed so far on speech-to-text, text-to-speech and the LLM.\n\nLive while the bot is in the call, final once it has left. key_sources says\nper provider whether the bot ran on the server's key (billed by Meeting\nBaaS) or on one the request brought. Only the API key that created the bot\nmay read it.", "operationId": "get_bot_usage_bots__bot_id__usage_get", "parameters": [ { "name": "bot_id", "in": "path", "required": true, "schema": { "type": "string", "title": "Bot Id" } } ], "responses": { "200": { "description": "Successful Response", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/UsageReport" } } } }, "404": { "description": "No usage recorded for that bot yet" }, "422": { "description": "Validation Error", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/HTTPValidationError" } } } } } } }, "/bots/{bot_id}/briefing": { "get": { "tags": [ "bots" ], "summary": "Get Bot Briefing", "description": "The post-meeting briefing: summary, decisions, actions, open items, what the\nbot said and what it escalated. Written once the call ends, on the bot's own\nLLM key; also delivered in the speaking_bot.ended event. Only the API key\nthat created the bot may read it.", "operationId": "get_bot_briefing_bots__bot_id__briefing_get", "parameters": [ { "name": "bot_id", "in": "path", "required": true, "schema": { "type": "string", "title": "Bot Id" } } ], "responses": { "200": { "description": "Successful Response", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/BriefingReport" } } } }, "404": { "description": "No briefing for that bot (yet)" }, "422": { "description": "Validation Error", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/HTTPValidationError" } } } } } } } }, "webhooks": { "speaking_bot.utterance": { "post": { "tags": [ "events" ], "summary": "Bot utterance", "description": "The bot finished saying something.\n\nOne event per spoken turn, including the entry message and anything\nrelayed from the owner. `data.text` is what went to text-to-speech.\n\nDelivered as an HTTP POST to the bot's `callback_url`, with the event name in the `x-speaking-bot-event` header and, when the bot was created with a `callback_secret`, `x-speaking-bot-signature: sha256=`: the HMAC-SHA256 of the exact request body with that secret. Answer with any 2xx. Network errors and 5xx are retried three times (after 1, 3 and 9 seconds); a redirect counts as a failed delivery and is not followed.", "operationId": "speaking_bot_utterance", "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/UtteranceEvent" } } }, "required": true }, "responses": { "200": { "description": "Received. Any 2xx counts as delivered.", "content": { "application/json": { "schema": {} } } }, "422": { "description": "Validation Error", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/HTTPValidationError" } } } } } } }, "speaking_bot.escalation": { "post": { "tags": [ "events" ], "summary": "Escalation raised", "description": "A representative bot handed a decision back to its owner.\n\nFires the moment the bot calls its escalate tool, before anyone has\nanswered. Reply with `POST /bots/{bot_id}/escalations/{escalation_id}/response`\nand the bot relays the answer to the meeting.\n\nDelivered as an HTTP POST to the bot's `callback_url`, with the event name in the `x-speaking-bot-event` header and, when the bot was created with a `callback_secret`, `x-speaking-bot-signature: sha256=`: the HMAC-SHA256 of the exact request body with that secret. Answer with any 2xx. Network errors and 5xx are retried three times (after 1, 3 and 9 seconds); a redirect counts as a failed delivery and is not followed.", "operationId": "speaking_bot_escalation", "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/EscalationEvent" } } }, "required": true }, "responses": { "200": { "description": "Received. Any 2xx counts as delivered.", "content": { "application/json": { "schema": {} } } }, "422": { "description": "Validation Error", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/HTTPValidationError" } } } } } } }, "speaking_bot.owner_message_delivered": { "post": { "tags": [ "events" ], "summary": "Owner message delivered", "description": "The bot relayed an owner message or an escalation answer to the meeting.\n\n`data.message_id` matches the `message_id` returned when it was queued.\n\nDelivered as an HTTP POST to the bot's `callback_url`, with the event name in the `x-speaking-bot-event` header and, when the bot was created with a `callback_secret`, `x-speaking-bot-signature: sha256=`: the HMAC-SHA256 of the exact request body with that secret. Answer with any 2xx. Network errors and 5xx are retried three times (after 1, 3 and 9 seconds); a redirect counts as a failed delivery and is not followed.", "operationId": "speaking_bot_owner_message_delivered", "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/OwnerMessageDeliveredEvent" } } }, "required": true }, "responses": { "200": { "description": "Received. Any 2xx counts as delivered.", "content": { "application/json": { "schema": {} } } }, "422": { "description": "Validation Error", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/HTTPValidationError" } } } } } } }, "speaking_bot.ended": { "post": { "tags": [ "events" ], "summary": "Bot ended", "description": "The bot has left the meeting; nothing follows this event.\n\nCarries the final usage report, the briefing when one was requested and\nevery escalation of the call with its answer. Unlike the others this one\nis awaited before the bot's process exits, so it is delivered even when\nthe call ends abruptly.\n\nDelivered as an HTTP POST to the bot's `callback_url`, with the event name in the `x-speaking-bot-event` header and, when the bot was created with a `callback_secret`, `x-speaking-bot-signature: sha256=`: the HMAC-SHA256 of the exact request body with that secret. Answer with any 2xx. Network errors and 5xx are retried three times (after 1, 3 and 9 seconds); a redirect counts as a failed delivery and is not followed.", "operationId": "speaking_bot_ended", "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/EndedEvent" } } }, "required": true }, "responses": { "200": { "description": "Received. Any 2xx counts as delivered.", "content": { "application/json": { "schema": {} } } }, "422": { "description": "Validation Error", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/HTTPValidationError" } } } } } } } }, "components": { "schemas": { "AcceptedResponse": { "properties": { "ok": { "type": "boolean", "title": "Ok", "default": true }, "message_id": { "type": "string", "title": "Message Id" } }, "type": "object", "required": [ "message_id" ], "title": "AcceptedResponse", "description": "The message was queued for the bot." }, "AuthorityConfig": { "properties": { "owner_name": { "type": "string", "maxLength": 120, "minLength": 1, "title": "Owner Name", "description": "Who the bot represents" }, "approved_positions": { "items": { "type": "string" }, "type": "array", "maxItems": 20, "title": "Approved Positions", "description": "Positions the bot may state, in the owner's words" }, "escalate_on": { "items": { "type": "string" }, "type": "array", "maxItems": 20, "title": "Escalate On", "description": "Decisions that must go back to the owner before any answer" }, "forbidden": { "items": { "type": "string" }, "type": "array", "maxItems": 20, "title": "Forbidden", "description": "Things the bot must never say or do, even if asked" } }, "additionalProperties": false, "type": "object", "required": [ "owner_name" ], "title": "AuthorityConfig", "description": "What the bot may say on its owner's behalf, and what it must hand back.\n\nTurns the persona into a representative: it introduces itself as an AI\nattending for ``owner_name``, states only ``approved_positions``, raises an\nescalation (and tells the room it is checking) for anything in\n``escalate_on``, and never does what ``forbidden`` lists. Spending,\ncommitments and deadline changes are escalated even when not listed." }, "BotCredentials": { "properties": { "llm_api_key": { "anyOf": [ { "type": "string", "minLength": 1, "format": "password", "writeOnly": true }, { "type": "null" } ], "format": "password", "title": "Llm Api Key", "description": "API key for the LLM provider selected by llm_provider (OpenAI, Anthropic or Z.ai).", "writeOnly": true }, "stt_api_key": { "anyOf": [ { "type": "string", "minLength": 1, "format": "password", "writeOnly": true }, { "type": "null" } ], "format": "password", "title": "Stt Api Key", "description": "Deepgram API key for speech-to-text.", "writeOnly": true }, "tts_api_key": { "anyOf": [ { "type": "string", "minLength": 1, "format": "password", "writeOnly": true }, { "type": "null" } ], "format": "password", "title": "Tts Api Key", "description": "Cartesia API key for text-to-speech.", "writeOnly": true } }, "additionalProperties": false, "type": "object", "title": "BotCredentials", "description": "Bring-your-own provider keys for one bot.\n\nEvery field is optional; a key that is not supplied falls back to the\nserver's own configuration. Keys are handed to this bot's pipeline process\nonly, are never written to disk or logs, and are never returned by the API." }, "BotRequest": { "properties": { "meeting_url": { "type": "string", "title": "Meeting Url", "description": "URL of the Google Meet, Zoom or Microsoft Teams meeting to join" }, "bot_name": { "type": "string", "title": "Bot Name", "description": "Name to display for the bot in the meeting", "default": "" }, "personas": { "anyOf": [ { "items": { "type": "string" }, "type": "array", "maxItems": 10 }, { "type": "null" } ], "title": "Personas", "description": "List of persona names to use. The first available will be selected." }, "bot_image": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "title": "Bot Image" }, "entry_message": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "title": "Entry Message" }, "extra": { "anyOf": [ { "additionalProperties": true, "type": "object" }, { "type": "null" } ], "title": "Extra" }, "enable_tools": { "type": "boolean", "title": "Enable Tools", "default": true }, "prompt": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "title": "Prompt" }, "websocket_url": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "title": "Websocket Url", "description": "Optional public WebSocket base URL override, e.g. wss://bot.example.com" }, "turn_config": { "anyOf": [ { "$ref": "#/components/schemas/TurnConfig" }, { "type": "null" } ], "description": "Per-bot turn-taking tuning (VAD confidence/start_secs/stop_secs/min_volume)" }, "prompt_data_sources": { "anyOf": [ { "items": { "$ref": "#/components/schemas/PromptDataSource" }, "type": "array", "maxItems": 10 }, { "type": "null" } ], "title": "Prompt Data Sources", "description": "External text or URL data sources to append to the bot prompt" }, "prompt_data_token_limit": { "type": "integer", "maximum": 50000.0, "minimum": 0.0, "title": "Prompt Data Token Limit", "description": "Approximate total token cap for loaded prompt_data_sources. 0 disables loading.", "default": 4000 }, "mcp": { "anyOf": [ { "$ref": "#/components/schemas/MCPConfig" }, { "type": "null" } ], "description": "MCP server/tool metadata and optional live connection details" }, "mcp_profile": { "anyOf": [ { "type": "string", "enum": [ "professional", "personal", "all" ] }, { "type": "null" } ], "title": "Mcp Profile", "description": "Optional trusted local mcpproxy group preset. 'professional' connects to MCP_PROXY_PROFESSIONAL_URL or http://127.0.0.1:8111/mcp; 'personal' connects to MCP_PROXY_PERSONAL_URL or http://127.0.0.1:8110/mcp; 'all' connects to MCP_PROXY_ALL_URL or http://127.0.0.1:8109/mcp. The preset is merged with explicit mcp servers when both are supplied." }, "mcp_profile_tool_access": { "type": "string", "enum": [ "read_only", "read_write" ], "title": "Mcp Profile Tool Access", "description": "Tool exposure for mcp_profile presets. 'read_only' exposes retrieve_tools, call_tool_read, read_cache, and set_profile. 'read_write' also exposes call_tool_write. Presets never expose upstream_servers, call_tool_destructive, code_execution, registry, or quarantine tools.", "default": "read_only" }, "llm_provider": { "anyOf": [ { "type": "string", "enum": [ "openai", "anthropic", "zai" ] }, { "type": "null" } ], "title": "Llm Provider", "description": "LLM provider for this bot. Defaults to LLM_PROVIDER, then openai." }, "llm_model": { "anyOf": [ { "type": "string", "maxLength": 120, "minLength": 1 }, { "type": "null" } ], "title": "Llm Model", "description": "Provider model for this bot. Defaults to provider-specific env vars." }, "speech_speed": { "anyOf": [ { "type": "number", "maximum": 1.5, "minimum": 0.6 }, { "type": "null" } ], "title": "Speech Speed", "description": "TTS speaking speed multiplier between 0.6 and 1.5; values outside are rejected. Defaults to CARTESIA_TTS_SPEED, TTS_SPEED, SPEECH_SPEED, or the runner default." }, "speech_volume": { "anyOf": [ { "type": "number", "maximum": 2.0, "minimum": 0.5 }, { "type": "null" } ], "title": "Speech Volume", "description": "TTS loudness multiplier. Honored range is 0.5-2.0 (Cartesia sonic-3). Omit for the provider default." }, "speech_emotion": { "anyOf": [ { "type": "string", "maxLength": 60, "minLength": 1 }, { "type": "null" } ], "title": "Speech Emotion", "description": "Emotion tag guiding the TTS tone (Cartesia sonic-3, experimental; 60+ tags such as 'excited', 'calm'). Omit to let the model infer tone from the text, which Cartesia recommends." }, "wake_phrases": { "anyOf": [ { "items": { "type": "string" }, "type": "array", "maxItems": 10 }, { "type": "null" } ], "title": "Wake Phrases", "description": "Other ways the bot's name may be heard, for respond_mode 'mentioned': spellings, nicknames, how the speech-to-text tends to write it. The name itself, split and joined variants of it, and these are all accepted, and all are boosted in the recogniser. Up to 10 phrases of at most 40 characters each." }, "respond_mode": { "type": "string", "enum": [ "always", "mentioned" ], "title": "Respond Mode", "description": "When the bot replies. 'always': every completed turn gets an answer (good for 1:1 calls). 'mentioned': the bot only hears turns within a short window after someone says its name \u2014 the mode for multi-party meetings where it should stay quiet until addressed.", "default": "always" }, "credentials": { "anyOf": [ { "$ref": "#/components/schemas/BotCredentials" }, { "type": "null" } ], "description": "Bring your own provider keys for this bot (LLM, speech-to-text, text-to-speech). Any key left out falls back to the server's own configuration. Keys are used only by this bot's pipeline and are never stored or returned." }, "transcription_enabled": { "type": "boolean", "title": "Transcription Enabled", "description": "Have MeetingBaas transcribe the recording once the meeting ends, with the bot's own turns attributed to it by name. Set false for a recording without a transcript.", "default": true }, "transcription_provider": { "type": "string", "enum": [ "gladia", "deepgram", "assemblyai", "speechmatics", "soniox" ], "title": "Transcription Provider", "description": "MeetingBaas speech-to-text provider for that transcript.", "default": "gladia" }, "language": { "anyOf": [ { "type": "string", "pattern": "^(multi|[a-z]{2,3}(-[A-Za-z0-9]{2,8})*)$" }, { "type": "null" } ], "title": "Language", "description": "Language the bot listens for, as a BCP-47 tag (en, en-NG, fr), or 'multi' to let Deepgram switch between its multilingual set during the call. Defaults to en-US." }, "callback_url": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "title": "Callback Url", "description": "Where this API posts the bot's own events: each utterance it speaks, each escalation to its owner, and the end of the call with the usage report and briefing. An https URL on a public host; signed with callback_secret when one is given. Redirects are not followed." }, "callback_secret": { "anyOf": [ { "type": "string", "minLength": 1, "format": "password", "writeOnly": true }, { "type": "null" } ], "format": "password", "title": "Callback Secret", "description": "Shared secret used to sign callback_url deliveries (x-speaking-bot-signature: sha256=).", "writeOnly": true }, "authority": { "anyOf": [ { "$ref": "#/components/schemas/AuthorityConfig" }, { "type": "null" } ], "description": "Make the bot a representative: who it attends for, what it may say, what it must escalate. Adds the escalate_to_owner tool and switches off unprompted speech." }, "briefing": { "anyOf": [ { "$ref": "#/components/schemas/BriefingConfig" }, { "type": "null" } ], "description": "Post-meeting briefing settings. Only bots that set this (even empty) get a briefing, in the call-end event and at GET /bots/{bot_id}/briefing." } }, "additionalProperties": false, "type": "object", "required": [ "meeting_url" ], "title": "BotRequest", "description": "Request model for creating a speaking bot in a meeting.", "example": { "authority": { "approved_positions": [ "Ada supports option B for the vendor choice" ], "escalate_on": [ "any spending above 500 dollars" ], "forbidden": [ "agreeing to new deadlines" ], "owner_name": "Ada Okafor" }, "bot_image": "https://example.com/bot-avatar.png", "bot_name": "Meeting Assistant", "briefing": { "language": "en" }, "callback_url": "https://app.example.com/hooks/speaking-bot", "enable_tools": true, "entry_message": "Hello! I'm here to assist with the meeting.", "extra": { "company": "ACME Corp", "meeting_purpose": "Weekly sync" }, "language": "en", "llm_model": "claude-opus-4-8", "llm_provider": "anthropic", "mcp": { "servers": [ { "name": "crm", "tool_allowlist": [ "get_account", "list_recent_calls" ], "tools": [ "get_account", "list_recent_calls" ], "transport": "streamable_http", "url": "https://mcp.example.com" } ] }, "mcp_profile": "professional", "mcp_profile_tool_access": "read_only", "meeting_url": "https://meet.google.com/abc-defg-hij", "personas": [ "helpful_assistant", "meeting_facilitator" ], "prompt": "You are Meeting Assistant, a concise and professional AI bot that helps summarize key points and keep the meeting on track. Speak clearly and stay on topic.", "prompt_data_sources": [ { "name": "CRM account notes", "type": "url", "url": "https://example.com/account-notes.md" } ], "prompt_data_token_limit": 3000, "speech_speed": 1.15, "websocket_url": "wss://bots.example.com" } }, "BriefingAction": { "properties": { "owner": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "title": "Owner" }, "task": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "title": "Task" }, "due": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "title": "Due" } }, "additionalProperties": true, "type": "object", "title": "BriefingAction" }, "BriefingConfig": { "properties": { "enabled": { "type": "boolean", "title": "Enabled", "description": "Generate a briefing when the call ends", "default": true }, "language": { "anyOf": [ { "type": "string", "pattern": "^(multi|[a-z]{2,3}(-[A-Za-z0-9]{2,8})*)$" }, { "type": "null" } ], "title": "Language", "description": "Language the briefing is written in (BCP-47). Defaults to English." }, "instructions": { "anyOf": [ { "type": "string", "maxLength": 2000 }, { "type": "null" } ], "title": "Instructions", "description": "What the owner wants the briefing to focus on" } }, "additionalProperties": false, "type": "object", "title": "BriefingConfig", "description": "The post-meeting briefing, generated on the bot's own LLM key." }, "BriefingEscalation": { "properties": { "question": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "title": "Question" }, "status": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "title": "Status" }, "answer": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "title": "Answer" } }, "additionalProperties": true, "type": "object", "title": "BriefingEscalation" }, "BriefingReport": { "properties": { "language": { "type": "string", "title": "Language", "default": "en" }, "summary": { "type": "string", "title": "Summary", "default": "" }, "decisions": { "items": { "type": "string" }, "type": "array", "title": "Decisions" }, "actions": { "items": { "$ref": "#/components/schemas/BriefingAction" }, "type": "array", "title": "Actions" }, "unresolved": { "items": { "type": "string" }, "type": "array", "title": "Unresolved" }, "what_the_representative_said": { "items": { "type": "string" }, "type": "array", "title": "What The Representative Said" }, "escalations": { "items": { "$ref": "#/components/schemas/BriefingEscalation" }, "type": "array", "title": "Escalations" }, "coverage_notes": { "items": { "type": "string" }, "type": "array", "title": "Coverage Notes" }, "generated_at": { "anyOf": [ { "type": "number" }, { "type": "null" } ], "title": "Generated At" }, "llm_provider": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "title": "Llm Provider" }, "llm_model": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "title": "Llm Model" } }, "additionalProperties": true, "type": "object", "title": "BriefingReport", "description": "The post-meeting briefing for the bot's owner." }, "EndedEvent": { "properties": { "event_id": { "type": "string", "title": "Event Id", "description": "Unique per delivery; use it to drop duplicates" }, "bot_id": { "type": "string", "title": "Bot Id", "description": "The MeetingBaas bot ID returned by POST /bots" }, "client_id": { "type": "string", "title": "Client Id", "description": "The server's internal ID for the bot" }, "created_at": { "type": "string", "format": "date-time", "title": "Created At", "description": "When the event was produced, ISO 8601 with offset" }, "event": { "type": "string", "const": "speaking_bot.ended", "title": "Event" }, "data": { "$ref": "#/components/schemas/EndedEventData" } }, "type": "object", "required": [ "event_id", "bot_id", "client_id", "created_at", "event", "data" ], "title": "EndedEvent", "description": "``speaking_bot.ended``: the bot has left; the last event for this bot." }, "EndedEventData": { "properties": { "status": { "type": "string", "enum": [ "completed", "failed" ], "title": "Status" }, "reason": { "type": "string", "title": "Reason", "description": "Why the bot stopped: 'call ended (...)', 'removed by caller', 'bot failed (...)' or 'never admitted'" }, "usage": { "anyOf": [ { "$ref": "#/components/schemas/UsageReport" }, { "type": "null" } ], "description": "The final usage report, when one was recorded" }, "briefing": { "anyOf": [ { "$ref": "#/components/schemas/BriefingReport" }, { "type": "null" } ], "description": "The briefing, when the bot was asked for one" }, "escalations": { "items": { "$ref": "#/components/schemas/Escalation" }, "type": "array", "title": "Escalations", "description": "Every escalation of the call, with answers" } }, "type": "object", "required": [ "status", "reason" ], "title": "EndedEventData" }, "Escalation": { "properties": { "escalation_id": { "type": "string", "title": "Escalation Id" }, "question": { "type": "string", "title": "Question", "description": "The exact decision asked for, with amounts, names and dates" }, "category": { "type": "string", "enum": [ "spending", "commitment", "approval", "scheduling", "information", "other" ], "title": "Category" }, "context": { "type": "string", "title": "Context", "description": "What led to the question and who asked, in one or two sentences", "default": "" }, "asked_by": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "title": "Asked By", "description": "The participant who asked, when known" }, "number": { "anyOf": [ { "type": "integer" }, { "type": "null" } ], "title": "Number", "description": "1-based position among this bot's escalations" }, "created_at": { "type": "number", "title": "Created At", "description": "Unix timestamp of when the bot raised it" }, "status": { "type": "string", "enum": [ "pending", "answered" ], "title": "Status", "default": "pending" }, "response": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "title": "Response", "description": "The owner's answer, once posted" }, "decision": { "anyOf": [ { "type": "string", "enum": [ "approved", "declined", "deferred", "info" ] }, { "type": "null" } ], "title": "Decision", "description": "How the owner decided, when it was a yes/no question" }, "answered_at": { "anyOf": [ { "type": "number" }, { "type": "null" } ], "title": "Answered At", "description": "Unix timestamp of the owner's answer" } }, "additionalProperties": true, "type": "object", "required": [ "escalation_id", "question", "category", "created_at" ], "title": "Escalation", "description": "A decision the bot handed back to its owner, with the answer once one came.\n\nReturned by ``GET /bots/{bot_id}/escalations``, carried by the\n``speaking_bot.escalation`` event when raised, and listed again in\n``speaking_bot.ended``." }, "EscalationEvent": { "properties": { "event_id": { "type": "string", "title": "Event Id", "description": "Unique per delivery; use it to drop duplicates" }, "bot_id": { "type": "string", "title": "Bot Id", "description": "The MeetingBaas bot ID returned by POST /bots" }, "client_id": { "type": "string", "title": "Client Id", "description": "The server's internal ID for the bot" }, "created_at": { "type": "string", "format": "date-time", "title": "Created At", "description": "When the event was produced, ISO 8601 with offset" }, "event": { "type": "string", "const": "speaking_bot.escalation", "title": "Event" }, "data": { "$ref": "#/components/schemas/Escalation" } }, "type": "object", "required": [ "event_id", "bot_id", "client_id", "created_at", "event", "data" ], "title": "EscalationEvent", "description": "``speaking_bot.escalation``: a representative bot handed a decision to its owner." }, "EscalationResponseRequest": { "properties": { "response": { "type": "string", "maxLength": 2000, "minLength": 1, "title": "Response" }, "decision": { "anyOf": [ { "type": "string", "enum": [ "approved", "declined", "deferred", "info" ] }, { "type": "null" } ], "title": "Decision", "description": "How the owner decided, when it was a yes/no question" } }, "additionalProperties": false, "type": "object", "required": [ "response" ], "title": "EscalationResponseRequest", "description": "The owner's answer to an escalation the bot raised." }, "HTTPValidationError": { "properties": { "detail": { "items": { "$ref": "#/components/schemas/ValidationError" }, "type": "array", "title": "Detail" } }, "type": "object", "title": "HTTPValidationError" }, "JoinResponse": { "properties": { "bot_id": { "type": "string", "title": "Bot Id", "description": "The MeetingBaas bot ID used for API operations with MeetingBaas" } }, "type": "object", "required": [ "bot_id" ], "title": "JoinResponse", "description": "Response model for a bot joining a meeting" }, "LeaveBotRequest": { "properties": { "bot_id": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "title": "Bot Id", "description": "The MeetingBaas bot ID to remove from the meeting. This will also close the WebSocket connection made through Pipecat by this bot." } }, "additionalProperties": false, "type": "object", "title": "LeaveBotRequest", "description": "Request model for making a bot leave a meeting" }, "LeaveResponse": { "properties": { "message": { "type": "string", "title": "Message", "description": "What was done" }, "status": { "type": "string", "enum": [ "success", "partial" ], "title": "Status", "description": "'partial' when MeetingBaas refused the leave but the local pipeline was still shut down" }, "bot_id": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "title": "Bot Id", "description": "The MeetingBaas bot ID that was removed" } }, "type": "object", "required": [ "message", "status" ], "title": "LeaveResponse", "description": "What ``DELETE /bots/{bot_id}`` answers once the removal was processed." }, "MCPConfig": { "properties": { "servers": { "items": { "$ref": "#/components/schemas/MCPServerConfig" }, "type": "array", "maxItems": 10, "title": "Servers", "description": "MCP servers to document and optionally connect for tool calls" }, "instructions": { "anyOf": [ { "type": "string", "maxLength": 4000 }, { "type": "null" } ], "title": "Instructions", "description": "Global MCP usage instructions for the bot" } }, "additionalProperties": false, "type": "object", "title": "MCPConfig", "description": "Bot-level MCP configuration: the set of servers to expose plus global instructions." }, "MCPServerConfig": { "properties": { "name": { "type": "string", "maxLength": 120, "minLength": 1, "title": "Name" }, "enabled": { "type": "boolean", "title": "Enabled", "description": "Whether this server may be used. Disabled servers are documented but not connected.", "default": true }, "url": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "title": "Url", "description": "Remote MCP server URL. Required for http, streamable_http, and sse transports." }, "headers": { "anyOf": [ { "additionalProperties": { "type": "string" }, "type": "object" }, { "type": "null" } ], "title": "Headers", "description": "Optional HTTP headers for remote MCP servers. Use only when a server requires them." }, "transport": { "anyOf": [ { "type": "string", "enum": [ "http", "streamable_http", "sse" ] }, { "type": "null" } ], "title": "Transport", "description": "Remote MCP transport. Omit for metadata-only servers that cannot execute tools." }, "tools": { "anyOf": [ { "items": { "type": "string" }, "type": "array", "maxItems": 50 }, { "type": "null" } ], "title": "Tools", "description": "Known tool names exposed by this MCP server" }, "tool_allowlist": { "anyOf": [ { "items": { "type": "string" }, "type": "array", "maxItems": 50 }, { "type": "null" } ], "title": "Tool Allowlist", "description": "Optional allowlist of MCP tool names this bot may call from this server." }, "timeout_seconds": { "anyOf": [ { "type": "number", "maximum": 300.0, "minimum": 0.1 }, { "type": "null" } ], "title": "Timeout Seconds", "description": "Optional per-server connection/tool timeout in seconds." }, "instructions": { "anyOf": [ { "type": "string", "maxLength": 4000 }, { "type": "null" } ], "title": "Instructions", "description": "Operator instructions or constraints for this MCP server" } }, "additionalProperties": false, "type": "object", "required": [ "name" ], "title": "MCPServerConfig", "description": "MCP server metadata and optional live connection details." }, "OwnerMessageDeliveredEvent": { "properties": { "event_id": { "type": "string", "title": "Event Id", "description": "Unique per delivery; use it to drop duplicates" }, "bot_id": { "type": "string", "title": "Bot Id", "description": "The MeetingBaas bot ID returned by POST /bots" }, "client_id": { "type": "string", "title": "Client Id", "description": "The server's internal ID for the bot" }, "created_at": { "type": "string", "format": "date-time", "title": "Created At", "description": "When the event was produced, ISO 8601 with offset" }, "event": { "type": "string", "const": "speaking_bot.owner_message_delivered", "title": "Event" }, "data": { "$ref": "#/components/schemas/OwnerMessageDeliveredEventData" } }, "type": "object", "required": [ "event_id", "bot_id", "client_id", "created_at", "event", "data" ], "title": "OwnerMessageDeliveredEvent", "description": "``speaking_bot.owner_message_delivered``: the bot relayed an owner message or escalation answer." }, "OwnerMessageDeliveredEventData": { "properties": { "message_id": { "type": "string", "title": "Message Id", "description": "The message_id returned when it was queued" }, "type": { "type": "string", "enum": [ "owner_message", "escalation_response" ], "title": "Type" }, "escalation_id": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "title": "Escalation Id", "description": "The escalation this answered, for escalation_response" } }, "type": "object", "required": [ "message_id", "type" ], "title": "OwnerMessageDeliveredEventData" }, "OwnerMessageRequest": { "properties": { "text": { "type": "string", "maxLength": 2000, "minLength": 1, "title": "Text" } }, "additionalProperties": false, "type": "object", "required": [ "text" ], "title": "OwnerMessageRequest", "description": "Something the owner wants the bot to relay to the meeting now." }, "PersonaImageRequest": { "type": "object", "required": [ "name", "description" ], "properties": { "name": { "type": "string", "description": "Name of the persona to generate an image for" }, "description": { "type": "string", "description": "Detailed description of the persona's appearance and characteristics" }, "gender": { "type": "string", "description": "Gender of the persona (optional)", "enum": [ "male", "female", "non-binary" ] }, "characteristics": { "type": "array", "items": { "type": "string" }, "description": "List of specific characteristics or features of the persona" } } }, "PersonaImageResponse": { "type": "object", "properties": { "name": { "type": "string", "description": "Name of the persona" }, "image_url": { "type": "string", "description": "URL of the generated image" }, "generated_at": { "type": "string", "format": "date-time", "description": "Timestamp when the image was generated" } } }, "PromptDataSource": { "properties": { "name": { "type": "string", "maxLength": 120, "minLength": 1, "title": "Name", "description": "Human-readable source name shown inside the prompt context block", "default": "external_context" }, "type": { "type": "string", "enum": [ "text", "url" ], "title": "Type", "description": "Whether to load inline text or fetch an external HTTP(S) URL" }, "text": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "title": "Text", "description": "Inline context. Required when type is text." }, "url": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "title": "Url", "description": "HTTP(S) URL to fetch. Required when type is url." }, "headers": { "anyOf": [ { "additionalProperties": { "type": "string" }, "type": "object" }, { "type": "null" } ], "title": "Headers", "description": "Optional HTTP headers for URL sources. Avoid request-specific secrets unless needed." }, "token_limit": { "anyOf": [ { "type": "integer", "maximum": 50000.0, "minimum": 1.0 }, { "type": "null" } ], "title": "Token Limit", "description": "Optional per-source token cap before the request-level cap is applied" } }, "additionalProperties": false, "type": "object", "required": [ "type" ], "title": "PromptDataSource", "description": "External context to append to the bot prompt under a token budget." }, "TurnConfig": { "properties": { "confidence": { "anyOf": [ { "type": "number", "maximum": 1.0, "minimum": 0.0 }, { "type": "null" } ], "title": "Confidence", "description": "VAD speech confidence threshold" }, "start_secs": { "anyOf": [ { "type": "number", "maximum": 5.0, "minimum": 0.05 }, { "type": "null" } ], "title": "Start Secs", "description": "Sustained speech (seconds) before a turn registers while the bot is silent; while it speaks, min_interrupt_words decides" }, "stop_secs": { "anyOf": [ { "type": "number", "maximum": 10.0, "minimum": 0.1 }, { "type": "null" } ], "title": "Stop Secs", "description": "Silence (seconds) before the bot checks whether the speaker is done; it replies right away when they are" }, "min_volume": { "anyOf": [ { "type": "number", "maximum": 1.0, "minimum": 0.0 }, { "type": "null" } ], "title": "Min Volume", "description": "Minimum input volume for VAD" }, "unfinished_pause_secs": { "anyOf": [ { "type": "number", "maximum": 10.0, "minimum": 0.2 }, { "type": "null" } ], "title": "Unfinished Pause Secs", "description": "When the speaker sounds mid-thought, silence (seconds) after which the bot replies anyway" }, "min_interrupt_words": { "anyOf": [ { "type": "integer", "maximum": 20.0, "minimum": 0.0 }, { "type": "null" } ], "title": "Min Interrupt Words", "description": "Words someone must say before they interrupt the bot mid-sentence; coughs and 'uh-huh's stay below it. 0 interrupts on any speech" } }, "additionalProperties": false, "type": "object", "title": "TurnConfig", "description": "Per-bot turn-taking tuning.\n\nAll fields optional; unset fields fall back to the VAD_* / TURN_* env\nvars, then the server defaults (0.2 s stop, 1.5 s unfinished pause). A\nlocal end-of-turn model decides whether the speaker has finished once the\nVAD reports a pause, so stop_secs only needs to catch the pause.\nHuman-facing bots want the defaults; bot-vs-bot meetings want patience\n(higher start_secs and unfinished_pause_secs) so the bots stop barging in\non each other." }, "UsageReport": { "properties": { "bot_id": { "type": "string", "title": "Bot Id" }, "meetingbaas_bot_id": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "title": "Meetingbaas Bot Id" }, "stt_provider": { "type": "string", "title": "Stt Provider" }, "tts_provider": { "type": "string", "title": "Tts Provider" }, "llm_provider": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "title": "Llm Provider" }, "llm_model": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "title": "Llm Model" }, "key_sources": { "additionalProperties": { "type": "string" }, "type": "object", "title": "Key Sources", "description": "Per provider: 'platform' (ran on the server's key) or 'caller'" }, "started_at": { "type": "number", "title": "Started At" }, "ended_at": { "anyOf": [ { "type": "number" }, { "type": "null" } ], "title": "Ended At" }, "duration_seconds": { "type": "number", "title": "Duration Seconds" }, "stt_audio_seconds": { "type": "number", "title": "Stt Audio Seconds" }, "tts_characters": { "type": "integer", "title": "Tts Characters" }, "tts_requests": { "type": "integer", "title": "Tts Requests" }, "llm_turns": { "type": "integer", "title": "Llm Turns" }, "llm_prompt_tokens": { "type": "integer", "title": "Llm Prompt Tokens" }, "llm_cached_prompt_tokens": { "type": "integer", "title": "Llm Cached Prompt Tokens" }, "llm_completion_tokens": { "type": "integer", "title": "Llm Completion Tokens" }, "llm_total_tokens": { "type": "integer", "title": "Llm Total Tokens" } }, "additionalProperties": true, "type": "object", "required": [ "bot_id", "stt_provider", "tts_provider", "started_at", "duration_seconds", "stt_audio_seconds", "tts_characters", "tts_requests", "llm_turns", "llm_prompt_tokens", "llm_cached_prompt_tokens", "llm_completion_tokens", "llm_total_tokens" ], "title": "UsageReport", "description": "What one bot consumed on each provider, from Pipecat's usage metrics." }, "UtteranceEvent": { "properties": { "event_id": { "type": "string", "title": "Event Id", "description": "Unique per delivery; use it to drop duplicates" }, "bot_id": { "type": "string", "title": "Bot Id", "description": "The MeetingBaas bot ID returned by POST /bots" }, "client_id": { "type": "string", "title": "Client Id", "description": "The server's internal ID for the bot" }, "created_at": { "type": "string", "format": "date-time", "title": "Created At", "description": "When the event was produced, ISO 8601 with offset" }, "event": { "type": "string", "const": "speaking_bot.utterance", "title": "Event" }, "data": { "$ref": "#/components/schemas/UtteranceEventData" } }, "type": "object", "required": [ "event_id", "bot_id", "client_id", "created_at", "event", "data" ], "title": "UtteranceEvent", "description": "``speaking_bot.utterance``: the bot finished saying something." }, "UtteranceEventData": { "properties": { "text": { "type": "string", "title": "Text", "description": "What the bot said, as sent to text-to-speech" }, "started_at": { "type": "number", "title": "Started At", "description": "Unix timestamp when the bot started speaking" }, "ended_at": { "type": "number", "title": "Ended At", "description": "Unix timestamp when it finished" } }, "type": "object", "required": [ "text", "started_at", "ended_at" ], "title": "UtteranceEventData" }, "ValidationError": { "properties": { "loc": { "items": { "anyOf": [ { "type": "string" }, { "type": "integer" } ] }, "type": "array", "title": "Location" }, "msg": { "type": "string", "title": "Message" }, "type": { "type": "string", "title": "Error Type" } }, "type": "object", "required": [ "loc", "msg", "type" ], "title": "ValidationError" } }, "securitySchemes": { "ApiKeyAuth": { "type": "apiKey", "in": "header", "name": "x-meeting-baas-api-key", "description": "MeetingBaas API key for authentication" } } }, "security": [ { "ApiKeyAuth": [] } ], "servers": [ { "url": "https://speaking.meetingbaas.com", "description": "Production server" }, { "url": "/", "description": "Local development server" } ] }