Step by step
Create the persona
ethora-agents-create-v2 { name, prompt, greetingMessage, llmProvider, llmModel, responseMode, cooldownSec } works in the hosted user session or B2B mode, not app-token mode. The LLM is chosen per agent and can be a self-hosted model behind an OpenAI-compatible endpoint. ethora-agents-list-v2 and ethora-agents-get-v2 read what exists; ethora-agents-clone-v2 duplicates one.
Put it in a room
ethora-agent-invite-to-chat { agentIdOrAddress, chatJid } lazily creates the bot instance for that agent and app and spawns its XMPP client live. For a multi-agent room call it once per agent; they all become members able to converse. Tune responseMode, responseProbability and cooldownSec with ethora-agents-update-v2 so they do not talk over each other.
Talk to it and inspect the instance
ethora-chats-message-v2 { text, roomJid, waitForReplySec: 45 } returns the reply. ethora-bot-instances-list { appId, agentId } shows running instances; ethora-bot-instance-diag returns live XMPP and ai-service status; ethora-bot-instance-test-message { text, roomJid } sends from the bot (every room it is in when roomJid is omitted); ethora-bot-instance-status { status } detaches or re-spawns it.
You: Policy Check is not answering in Members. What is wrong?
Assistant: ethora-bot-instances-list { agentId } ... one instance, status off.
ethora-bot-instance-diag { agentIdOrAddress, botInstanceId } ... xmpp: disconnected.
ethora-bot-instance-status { botInstanceId, status: "on" } ... re-spawned.Make it the default responder
ethora-agents-activate-v2 { agentId, chatJid } sets the app’s default bot instance and botStatus: on, which the widget session endpoint uses to decide who answers visitors. The agent must already be in a room of that app, otherwise 404. Then ethora-widget-embed-snippet produces the script tag.
Shape its identity over time
ethora-agent-soul-set { agentIdOrAddress, soulMd } replaces the agent’s SOUL.MD, its evolving identity and private notes; ethora-agent-soul-append { append } adds a fragment. Operators drive it from MCP, and the agent can self-edit through the same endpoint when the ai-service calls it. Keep the system prompt for instructions and SOUL.MD for what the agent learns.
Control who can use it, and move it
ethora-agent-set-visibility { visibility } takes private, unlisted or public; public agents can be invited cross-app by anyone who knows the address. ethora-agents-export-v2 { format: “json” } returns a portable bundle and ethora-agents-import-v2 { bundle, ownerAppId } recreates it in another app or tenant.
The tools this uses
Names and descriptions come from the server’s own tool list. Read-only tools are safe to auto-approve; destructive ones make your client ask first. Full reference.
| Tool | Name | What it does | Access |
|---|---|---|---|
| Create Agent | ethora-agents-create-v2 | Create a reusable AI agent (POST /v2/apps/:appId/agents). | write |
| List Agents | ethora-agents-list-v2 | List the reusable saved agents of an app (GET /v2/apps/:appId/agents, or GET /v2/agents for the token’s own app) - a saved agent is a reusable bot definition. | read-only |
| Update Agent | ethora-agents-update-v2 | Update a saved AI agent (PUT /v2/agents/:agentId). | write |
| Activate Agent for Widget | ethora-agents-activate-v2 | Make an agent the app’s ACTIVE widget bot: sets App.defaultBotInstanceId (and botStatus: on), which is what POST /v2/widget/sessions uses to decide who answers... | write |
| Export Agent | ethora-agents-export-v2 | Export an Agent as a portable bundle (GET /v2/agents/:idOrAddress/export). | read-only |
| Import Agent | ethora-agents-import-v2 | Import an Agent from a bundle produced by ethora-agents-export-v2 (POST /v2/agents/import, application/json body IS the bundle). | write |
| Invite Agent to Chat | ethora-agent-invite-to-chat | Invite an Agent into a chat room. | write |
| Set Agent Visibility | ethora-agent-set-visibility | Set an Agent’s visibility (private | unlisted | public). | write |
| Append to Agent Prompt | ethora-agent-soul-append | Append a fragment to an Agent’s SOUL.MD (its evolving identity / private notes). | write |
| List Bot Instances | ethora-bot-instances-list | List BotInstances. | read-only |
| Diagnose Bot Instance | ethora-bot-instance-diag | Diagnose a specific BotInstance for an Agent (GET /v2/agents/:idOrAddress/bot-instances/:botInstanceId/diag). | read-only |
| Widget Embed Snippet | ethora-widget-embed-snippet | Generate the <script> tag that embeds the Ethora AI chat widget (the floating launcher + chat panel that website visitors use) for an app, plus the prerequisites that... | read-only |
Two agents in one room, one on the website
“In my Studio Support app create two agents: Concierge, warm, answers booking questions and replies to everything; and Policy Check, which only speaks when asked about refunds or cancellations, at most once a minute. Put both in Members, ask about a refund, make Concierge the widget responder and export Policy Check for my other app.”
ethora-agents-create-v2{ name: "Concierge", prompt: "Warm front-of-house host for a dance studio. Answer booking questions.", responseMode: "always" }ethora-agents-create-v2{ name: "Policy Check", prompt: "Only answer refund and cancellation questions, citing studio policy.", responseMode: "mention", cooldownSec: 60 }ethora-agent-invite-to-chat{ agentIdOrAddress: "66f2b1c2d3e4f5a6b7c8d9e0", chatJid: "66f2b0a1b2c3d4e5f6a7b8c9_members" }ethora-agent-invite-to-chat{ agentIdOrAddress: "66f2b1c2d3e4f5a6b7c8d9e1", chatJid: "66f2b0a1b2c3d4e5f6a7b8c9_members" }ethora-chats-message-v2{ text: "Can I get a refund on a class pack?", roomJid: "66f2b0a1b2c3d4e5f6a7b8c9_members", waitForReplySec: 45 }ethora-agents-activate-v2{ agentId: "66f2b1c2d3e4f5a6b7c8d9e0", chatJid: "66f2b0a1b2c3d4e5f6a7b8c9_members" }ethora-agents-export-v2{ agentIdOrAddress: "66f2b1c2d3e4f5a6b7c8d9e1", format: "json" }ethora-agents-import-v2{ bundle: <bundle from the export>, ownerAppId: "66f2c0d1e2f3a4b5c6d7e8f9" }
Two live bot instances in Members with different response gates, Concierge on the website, and a Policy Check copy in the second app.
Good to know
ethora-agents-delete-v2removes the agent and all its bot instances; gated behind the dangerous-tools flag and flagged destructive.ethora-agents-clone-v2returns 422 if the overriddenslugcollides.ethora-bot-instance-test-messageneeds the ai-service running;ethora-bot-instance-leave-chatis the inverse of the invite and flagged destructive.- The legacy per-app bot tools return 422
BOT_NOT_INITIALIZEDon API-created apps.
