# API Documentation Source: https://docs.xpander.ai/api-reference/index REST API, Python SDK, and MCP Protocol for building and managing AI agents Choose your integration method based on your use case: **Platform REST API** Universal HTTP endpoints for managing agents, tasks, and knowledge bases from any programming language. **SDK for Building Agents** Comprehensive Python library with decorators, event handling, and framework integration for building sophisticated AI agents. **MCP for Claude & IDEs** Expose agents and tools as MCP servers for Claude Desktop, Cursor, and other MCP clients. ## Quick Comparison | Feature | REST API | Python SDK | Model Context Protocol | | -------------------- | ----------------------------- | ---------------------------- | ----------------------------- | | **Language Support** | Any language | Python only | Any MCP client | | **Primary Use Case** | Control plane operations | Building agents | Discovering & invoking agents | | **Setup Complexity** | Minimal (API key) | pip install | MCP client config | | **Best For** | CRUD operations, integrations | Agent development, workflows | IDE/AI client integration | | **Real-time** | Polling or webhooks | Event decorators | Server-Sent Events | ## Getting Started Sign up at [chat.xpander.ai](https://chat.xpander.ai) and generate your API key from the dashboard * **REST API**: For universal access from any language * **Python SDK**: For building agents in Python * **MCP Protocol**: For IDE and AI client integration Each integration method has comprehensive documentation, examples, and quick start guides ## REST API - Platform The REST API provides complete control over your resources: ```bash theme={"dark"} # List agents curl -X GET "https://api.xpander.ai/v1/agents" \ -H "x-api-key: YOUR_API_KEY" # Invoke an agent curl -X POST "https://api.xpander.ai/v1/agents/{agent_id}/invoke" \ -H "x-api-key: YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"input": {"text": "Analyze this data"}}' ``` View complete REST API documentation with all endpoints ## Python SDK - Build Agents The Python SDK enables rapid agent development with powerful abstractions: ```python theme={"dark"} from xpander_sdk import Agents, on_task # Initialize SDK agents = Agents() # Define task handler @on_task async def handle_task(task): print(f"Processing: {task.id}") task.result = "Task completed" return task # List and invoke agents agent = await agents.aget("agent-id") task = await agent.acreate_task(prompt="Analyze data") ``` View complete SDK documentation with modules and examples ## Model Context Protocol - Expose to Claude & IDEs Connect your agents and tools to Claude Desktop, Cursor, and other MCP clients: ```json theme={"dark"} { "mcpServers": { "xpander.ai": { "command": "npx", "args": [ "-y", "mcp-remote@latest", "https://api.xpander.ai/mcp/", "--header", "x-api-key:YOUR_API_KEY" ] } } } ``` View complete MCP setup guide with examples ## Authentication All integration methods use API key authentication: ```bash theme={"dark"} export XPANDER_API_KEY="your-api-key" ``` Get your API key from the [dashboard](https://platform.xpander.ai). ## Common Use Cases **Use Python SDK** for building agents with complex workflows, tool integrations, and event handling. The SDK provides decorators and lifecycle management for sophisticated agent architectures. **Use REST API** for integrating xpander into existing applications written in any language. Perfect for microservices, web apps, and mobile applications. **Use Model Context Protocol** for accessing agents from Claude Desktop, Cursor, VSCode, or any MCP-compatible client. Enables seamless agent discovery and invocation from your development environment. **Combine all three**: Build agents with the SDK, manage them via REST API, and access them through MCP clients. All methods work together seamlessly. ## API Resources Browse all REST API endpoints Explore SDK modules and classes View code examples and tutorials Complete platform documentation ## Support & Community Join our community Developer discussions View source code # Invoke an Agent via API Source: https://docs.xpander.ai/api-reference/invoke-api Call any xpander agent using a simple HTTP request with curl or any HTTP client. ## Base URL ```text theme={"dark"} https://api.xpander.ai/v1/agents/{agent_id}/invoke ``` ## Authentication All requests require an API key passed as a header: ```text theme={"dark"} x-api-key: YOUR_XPANDER_API_KEY ``` `Authorization: Bearer` is **not** supported. Use `x-api-key` only. ## Request Body | Field | Type | Required | Description | | ------------------ | ------ | -------- | --------------------------------------- | | `input.text` | string | ✅ | The prompt to send to the agent | | `input.user.id` | string | ✅ | The xpander user ID | | `input.user.email` | string | ✅ | The user's email address | | `user_oidc_token` | string | ⬜ | OAuth token for MCP-authenticated tools | ## Examples ### Synchronous Invocation Waits for the agent to complete and returns the result inline. ```bash theme={"dark"} curl -X POST "https://api.xpander.ai/v1/agents/{agent_id}/invoke" \ -H "Content-Type: application/json" \ -H "x-api-key: YOUR_XPANDER_API_KEY" \ -d '{ "input": { "text": "Your prompt here", "user": { "id": "USER_ID", "email": "user@example.com" } } }' ``` ### With MCP OAuth Token If the agent uses tools that require OAuth (e.g. Notion, Google Calendar), pass the user's OIDC token: ```bash theme={"dark"} curl -X POST "https://api.xpander.ai/v1/agents/{agent_id}/invoke" \ -H "Content-Type: application/json" \ -H "x-api-key: YOUR_XPANDER_API_KEY" \ -d '{ "input": { "text": "Your prompt here", "user": { "id": "USER_ID", "email": "user@example.com" } }, "user_oidc_token": "USER_OAUTH_TOKEN" }' ``` ### Asynchronous Invocation Fire-and-forget — returns immediately with a task ID. Poll for results separately. ```bash theme={"dark"} curl -X POST "https://api.xpander.ai/v1/agents/{agent_id}/invoke/async" \ -H "Content-Type: application/json" \ -H "x-api-key: YOUR_XPANDER_API_KEY" \ -d '{ "input": { "text": "Your prompt here", "user": { "id": "USER_ID", "email": "user@example.com" } } }' ``` ## Response ```json theme={"dark"} { "id": "task-uuid", "agent_id": "agent-uuid", "status": "completed", "result": "Agent response here", "source": "api", "created_at": "2026-04-10T17:34:09.655630Z", "finished_at": "2026-04-10T17:34:18.685730Z" } ``` ### Status values | Status | Meaning | | ----------- | ----------------------------------- | | `pending` | Task queued | | `executing` | Agent is running | | `completed` | Finished successfully | | `error` | Failed — check `result` for details | ## What NOT to Use | ❌ Doesn't work | ✅ Use instead | | ------------------------------------------- | -------------------------------------- | | `Authorization: Bearer ` | `x-api-key: ` | | `webhook.xpander.ai` (wraps body as string) | `api.xpander.ai/v1/agents/{id}/invoke` | | `input.user` with only `id` | Include both `id` and `email` | # Invoke a Connector via API Source: https://docs.xpander.ai/api-reference/invoke-connector-api Find a connector, get its connection, list its operations, and invoke any operation with curl — no agent or task required. Every connector you set up at [chat.xpander.ai/connectors](https://chat.xpander.ai/connectors) can be called directly over REST. This page walks the full path end to end: **find the connector → get its `connection_id` → pick an operation → invoke it**. ## Base URL & Authentication ```text theme={"dark"} https://api.xpander.ai ``` All requests require an API key passed as a header: ```text theme={"dark"} x-api-key: YOUR_XPANDER_API_KEY ``` Your API key is already scoped to your organization — you do **not** need to pass an organization ID. ## The three IDs you need | ID | What it is | Where to get it | | --------------- | ----------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------- | | `connector_id` | The connector itself (e.g. Firecrawl) | The URL at `chat.xpander.ai/connectors/{connector_id}`, or [List Tools](/api-reference/v1/tools/list-tools) | | `connection_id` | Your org's authenticated connection to that connector | The `connections[].id` field in [List Tools](/api-reference/v1/tools/list-tools) | | `operation_id` | The specific action to run | [List Connector Operations](/api-reference/v1/tools/list-connector-operations) — accepts the operation's `id` **or** its `operationId` | The connector page URL in the app gives you the `connector_id` — but invoking also requires a `connection_id`, which is a different UUID. Step 1 below shows how to get it. ## Step 1 — Find the connector and its connection Search your tool catalog by name: ```bash theme={"dark"} curl "https://api.xpander.ai/v1/tools?type=connector&query=firecrawl" \ -H "x-api-key: YOUR_XPANDER_API_KEY" ``` ```json theme={"dark"} { "items": [ { "kind": "connector", "id": "11111111-2222-3333-4444-555555555555", "name": "Firecrawl", "status": "ready", "total_operations": 6, "using_built_in_auth": true, "connections": [ { "id": "aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee", "name": "Firecrawl", "access_scope": "organizational" } ] } ], "total": 1 } ``` Here `items[].id` is the **`connector_id`** and `items[].connections[].id` is the **`connection_id`**. An empty `connections` array means the connector isn't connected yet — create a connection first with [Connect Connector](/api-reference/v1/tools/connect-connector) (OAuth2 connectors return a `connector_page_url` to finish auth in the browser). ## Step 2 — List the operations ```bash theme={"dark"} curl "https://api.xpander.ai/v1/tools/connectors/{connector_id}/operations?connection_id={connection_id}" \ -H "x-api-key: YOUR_XPANDER_API_KEY" ``` ```json theme={"dark"} [ { "id": "67e2daf399f31f9c55d127a7", "operationId": "FirecrawlScrapingServiceExtractWebpageContent", "path": "/scrape", "method": "post", "pretty_name": "Extract Webpage Content", "pretty_description": "Extracts content from a specified webpage URL." } ] ``` Either `id` or `operationId` works as the `operation_id` in the next steps. ## Step 3 (optional) — Inspect the operation's inputs ```bash theme={"dark"} curl "https://api.xpander.ai/v1/tools/connectors/{connector_id}/connections/{connection_id}/{operation_id}/schema" \ -H "x-api-key: YOUR_XPANDER_API_KEY" ``` The response's `input` field is a JSON schema with three groups — `body_params`, `query_params`, and `path_params` — which is exactly the structure the invoke call accepts. ## Step 4 — Invoke ```bash theme={"dark"} curl -X POST "https://api.xpander.ai/v1/tools/connectors/{connector_id}/connections/{connection_id}/{operation_id}" \ -H "x-api-key: YOUR_XPANDER_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "body_params": { "url": "https://example.com", "formats": ["markdown"] } }' ``` The response is the **target API's response**, passed through unchanged: ```json theme={"dark"} { "success": true, "data": { "markdown": "# Example Domain\n\nThis domain is for use in documentation examples...", "metadata": { "title": "Example Domain", "sourceURL": "https://example.com", "statusCode": 200 } } } ``` ### How the request body maps to the target API | Field | Purpose | Example | | -------------- | ------------------------------------ | -------------------------------- | | `body_params` | The JSON body sent to the target API | `{"url": "https://example.com"}` | | `query_params` | Query-string parameters, by name | `{"limit": 10}` | | `path_params` | Path parameters, by name | `{"crawlJobId": "abc123"}` | | `headers` | Extra headers for the target API | `{"Accept": "text/csv"}` | All four fields are optional — send only what the operation's schema requires. The operation always runs with its spec-defined HTTP method (a GET operation stays a GET), even though you call this endpoint with POST. The connection's stored credentials are applied automatically, and the call times out after 300 seconds. You can pass `_` as the `connector_id` and it will be resolved from the connection: `POST /v1/tools/connectors/_/connections/{connection_id}/{operation_id}` ## Common mistakes | ❌ Doesn't work | ✅ Use instead | | --------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------- | | Using the connector page URL's UUID as `connection_id` | That UUID is the `connector_id`; get `connection_id` from [List Tools](/api-reference/v1/tools/list-tools) | | `Authorization: Bearer ` with an API key | `x-api-key: ` | | Putting the target API's arguments at the top level of the body | Wrap them in `body_params` / `query_params` / `path_params` | | `GET /v1/tools/search?query=...` without `type` | Always pass `type` as well, e.g. `?query=firecrawl&type=connector` | # Model Context Protocol Source: https://docs.xpander.ai/api-reference/mcp Expose agents and tools as MCP servers for Claude Desktop, Cursor, and other MCP clients The Model Context Protocol (MCP) integration allows you to expose your agents and tools as MCP servers that can be connected to Claude Desktop, Cursor, VSCode, and any MCP-compatible client. ## Overview xpander provides three ways to use MCP: Pick and choose tools from multiple connectors and expose them as a single MCP server Expose your AI agents as MCP servers that can be invoked from MCP clients Expose an entire connector (like Slack or GitHub) as an MCP server ## MCP Server Endpoints Two endpoints are available: **Standard MCP:** ``` https://api.xpander.ai/mcp/ ``` **Server-Sent Events (SSE):** ``` https://api.xpander.ai/mcp/sse ``` Authentication is provided via your API key in the request headers. OAuth authentication (without API key) is coming soon! Your API key is a sensitive credential. Never share it publicly or commit it to version control. ## Configuration for Claude Desktop Add the MCP server to Claude Desktop by editing: ``` ~/Library/Application Support/Claude/claude_desktop_config.json ``` Basic configuration format: ```json theme={"dark"} { "mcpServers": { "xpander.ai": { "command": "npx", "args": [ "-y", "mcp-remote@latest", "https://api.xpander.ai/mcp/", "--header", "x-api-key:YOUR_API_KEY" ] } } } ``` Replace `YOUR_API_KEY` with your actual API key from [platform.xpander.ai](https://platform.xpander.ai). ## Quick Setup Get your API key from [platform.xpander.ai](https://platform.xpander.ai) Edit `~/Library/Application Support/Claude/claude_desktop_config.json`: ```json theme={"dark"} { "mcpServers": { "xpander.ai": { "command": "npx", "args": [ "-y", "mcp-remote@latest", "https://api.xpander.ai/mcp/", "--header", "x-api-key:YOUR_API_KEY" ] } } } ``` Restart Claude Desktop to load the new configuration Ask Claude: "What agents are available?" or "List my tools" ## Available Tools Once connected, Claude Desktop and other MCP clients can use these tools: * **List agents** - List all available agents in your organization * **Invoke agent** - Execute an agent task * **Create task** - Create a new task for an agent * **Get task** - Retrieve task details and status * **Get agent threads** - Get conversation threads for an agent * **Get thread messages** - Retrieve messages from a specific thread ## Use Case 1: MCP Composition Create custom MCP servers with specific tools from the xpander console at [chat.xpander.ai](https://chat.xpander.ai): 1. Go to **MCP Servers** → **New MCP Server** 2. Select specific tools from multiple connectors 3. Get a custom MCP URL for that composition 4. Use the same configuration format with the custom URL ## Use Case 2: Agents as MCP Enable MCP for specific agents: 1. In agent settings, go to **Task Sources** tab 2. Enable the **MCP** toggle 3. Get agent-specific MCP configuration 4. Claude can invoke that specific agent ## Use Case 3: Single Connector Expose individual connectors (Slack, GitHub, etc.) as MCP servers: 1. Go to **Settings** → **Connectors** 2. Select a connector 3. Click **MCP Configuration** 4. Get connector-specific MCP URL ## Authentication If you've already authenticated connectors in xpander (Gmail, LinkedIn, Slack, etc.), they work automatically through MCP without additional authentication in Claude. ## Testing Your MCP Integration After configuration, test by asking Claude: * "What agents are available?" * "List my agents" * "Invoke my data analysis agent to analyze this data" * "Create a task for my support agent" * "What's the status of task xyz?" Claude will use the MCP tools to interact with your agents and tasks. ## Example Configurations ```json theme={"dark"} { "mcpServers": { "xpander.ai": { "command": "npx", "args": [ "-y", "mcp-remote@latest", "https://api.xpander.ai/mcp/", "--header", "x-api-key:YOUR_API_KEY" ] } } } ``` ```json theme={"dark"} { "mcpServers": { "xpander.ai": { "command": "npx", "args": [ "-y", "mcp-remote@latest", "https://api.xpander.ai/mcp/sse", "--header", "x-api-key:YOUR_API_KEY" ] } } } ``` Replace `YOUR_API_KEY` with your own credentials. Never commit API keys to version control. ## Supported MCP Clients xpander MCP servers work with: * **Claude Desktop** - Anthropic's desktop application * **Cursor** - AI-powered code editor * **VSCode** - With MCP extension * **Any MCP-compatible client** - Following the Model Context Protocol specification ## Roadmap **Coming Soon**: OAuth authentication support, allowing you to connect without manually managing API keys. ## Next Steps Complete MCP setup with screenshots Manage agents via REST API Build agents with the SDK # Platform REST API Source: https://docs.xpander.ai/api-reference/rest-api Universal REST API for managing agents, tasks, and knowledge bases The REST API provides comprehensive HTTP endpoints for managing your AI agents, executing tasks, and controlling knowledge bases from any programming language. ## Overview The REST API is your control plane for the xpander platform, enabling you to: * **Manage Agents**: Create, update, deploy, and delete AI agents * **Agent Workspace**: Run bash commands, edit files, search code, and share artifacts inside a per-agent workspace * **Manage Workflows**: Build and run multi-agent orchestration workflows * **Connectors**: Connect to external services, search and manage operations * **Custom Functions**: Create, generate, and execute user-defined Python tools * **Export & Import**: Share agents as templates across organizations * **Execute Tasks**: Invoke agents and workflows synchronously, asynchronously, or with streaming * **Control Knowledge**: Manage knowledge bases and documents * **Access Toolkits**: List and invoke tools across integrations * **LLM Providers**: Discover available LLM providers and models ## Base URL ``` https://api.xpander.ai ``` ## Authentication All API requests require authentication via the `x-api-key` header: ```bash theme={"dark"} curl -X GET "https://api.xpander.ai/v1/agents" \ -H "x-api-key: YOUR_API_KEY" ``` ## Quick Start ```bash cURL theme={"dark"} # List all agents curl -X GET "https://api.xpander.ai/v1/agents" \ -H "x-api-key: YOUR_API_KEY" # Invoke an agent curl -X POST "https://api.xpander.ai/v1/agents/{agent_id}/invoke" \ -H "x-api-key: YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "input": { "text": "Analyze this data" } }' ``` ```python Python theme={"dark"} import requests API_KEY = "your-api-key" BASE_URL = "https://api.xpander.ai/v1" # List all agents response = requests.get( f"{BASE_URL}/agents", headers={"x-api-key": API_KEY} ) agents = response.json() # Invoke an agent response = requests.post( f"{BASE_URL}/agents/{agent_id}/invoke", headers={"x-api-key": API_KEY}, json={"input": {"text": "Analyze this data"}} ) result = response.json() ``` ```javascript JavaScript theme={"dark"} const API_KEY = 'your-api-key'; const BASE_URL = 'https://api.xpander.ai/v1'; // List all agents const agents = await fetch(`${BASE_URL}/agents`, { headers: { 'x-api-key': API_KEY } }).then(r => r.json()); // Invoke an agent const result = await fetch(`${BASE_URL}/agents/${agentId}/invoke`, { method: 'POST', headers: { 'x-api-key': API_KEY, 'Content-Type': 'application/json' }, body: JSON.stringify({ input: { text: 'Analyze this data' } }) }).then(r => r.json()); ``` ## API Endpoints Create, manage, and invoke AI agents Run commands, edit files, and share artifacts in a per-agent workspace Build and run multi-agent orchestration workflows Discover connectors, connect, inspect operation schemas, and invoke operations Create and execute user-defined Python tools Monitor and manage task executions Manage knowledge bases and documents Discover available LLM providers and models ## Key Features * **🌐 Universal Access**: Works with any programming language that supports HTTP * **⚡ Multiple Execution Modes**: Sync, async, and streaming invocation * **📊 Complete CRUD**: Full lifecycle management for all resources * **🔒 Secure**: API key authentication with organization-level scoping * **📖 OpenAPI Spec**: Complete OpenAPI 3.1 specification available ## Response Format All API responses follow a consistent JSON structure: ```json theme={"dark"} { "id": "resource-id", "status": "completed", "created_at": "2025-11-05T20:00:00Z", ... } ``` ## Error Handling The API uses standard HTTP status codes: * `200` - Success * `201` - Created * `400` - Bad Request * `401` - Unauthorized * `404` - Not Found * `422` - Validation Error * `500` - Internal Server Error Error responses include detailed information: ```json theme={"dark"} { "detail": [ { "loc": ["body", "input"], "msg": "field required", "type": "value_error.missing" } ] } ``` ## Rate Limits The API implements rate limiting to ensure fair usage: * **Standard**: 100 requests per minute * **Burst**: 1000 requests per hour Rate limit headers are included in responses: ``` X-RateLimit-Limit: 100 X-RateLimit-Remaining: 95 X-RateLimit-Reset: 1699200000 ``` ## Next Steps Explore agent management endpoints Build multi-agent orchestrations View code examples Download OpenAPI specification # Create Agent Source: https://docs.xpander.ai/api-reference/v1/agents/create-agent POST /v1/agents Create a new AI agent with specified configuration, tools, and knowledge bases Create a new AI agent with custom configuration. The agent will be created and ready for configuration and deployment. ## Request Body Display name for the agent Description of the agent's purpose and capabilities Deployment infrastructure: `serverless`. LLM provider: `openai` (default), `anthropic`, etc. Specific model version (e.g., `gpt-4o`, `gpt-4.1`) Emoji icon for the agent (e.g., "🚀", "📊") System instructions configuration Array of role descriptions for the agent Array of goal descriptions for the agent General instructions text Access control scope for the agent. Determines who can see and use the agent. Possible values: `personal` (visible only to the creator) or `organizational` (visible to the entire organization). Defaults to `organizational` if not specified. Target environment ID (optional) Use Nvidia NeMo (default: false) Custom API base URL for LLM provider (for AI Gateway configurations) Custom HTTP headers to include in LLM requests for gateway integration Reasoning effort level for the LLM (e.g., `low`, `medium`, `high`) Agent type: `manager` (default), `regular`, `a2a`, `curl` Output format: `text` (default) or `json` JSON schema for structured output when `output_format` is `json` Natural-language description of the desired output Agent framework (e.g., `agno`) Array of connector tool attachments with connection IDs and selected operation IDs Agent workflow graph configuration defining tool execution order Array of knowledge base IDs to attach to the agent Advanced agent settings including memory, session storage, tool limits, and safety features Task-level strategies for retry, stop conditions, and iteration Notification configuration (Slack, email, webhook) for agent events Deep planning configuration for complex multi-step tasks Voice ID for text-to-speech output Source node configurations (e.g., Slack, web UI triggers) Whether the agent requires human approval for tool calls ## Response Returns a complete `AIAgent` object: Unique identifier for the created agent (UUID) Display name of the agent Agent description Emoji icon representing the agent Current deployment status: `ACTIVE` or `INACTIVE` UUID of the organization that owns this agent Deployment infrastructure: `serverless` or `null` System instructions configuration Access control scope: `personal` or `organizational` AI model provider (e.g., `openai`) Specific model version (e.g., `gpt-4o`, `gpt-4.1`) Agent framework used (e.g., `agno`) Auto-generated human-friendly slug identifier (e.g., "beige-swallow") Agent version number Array of tools available to the agent Array of knowledge bases attached to the agent Agent workflow graph configuration Auto-generated webhook URL for agent invocations ## Example Request Minimal create request (required fields only): ```bash theme={"dark"} curl -X POST "https://api.xpander.ai/v1/agents" \ -H "Content-Type: application/json" \ -H "x-api-key: " \ -d '{ "name": "Customer Support Agent", "model_provider": "openai", "model_name": "gpt-5.2" }' ``` With full configuration: ```bash theme={"dark"} curl -X POST "https://api.xpander.ai/v1/agents" \ -H "Content-Type: application/json" \ -H "x-api-key: " \ -d '{ "name": "Customer Support Agent", "model_provider": "openai", "model_name": "gpt-5.2", "instructions": { "role": ["Customer support specialist"], "goal": ["Resolve customer issues efficiently"], "general": "Be helpful, professional, and empathetic" }, "access_scope": "organizational" }' ``` ## Example Response ```json theme={"dark"} { "id": "", "unique_name": "jade-bass", "name": "Customer Support Agent", "description": "", "deployment_type": "serverless", "framework": "agno", "status": "ACTIVE", "model_provider": "openai", "model_name": "gpt-5.2", "organization_id": "", "version": 2, "has_pending_changes": false, "is_latest": false, "tools": [], "instructions": { "role": [], "goal": [], "general": "" }, "access_scope": "organizational", "knowledge_bases": [], "icon": "🚀", "agno_settings": { "session_storage": true, "agent_memories": false, "agentic_culture": false, "user_memories": false, "agentic_memory": false, "session_summaries": false, "num_history_runs": 10, "max_tool_calls_from_history": 0, "tool_call_limit": 0, "coordinate_mode": true, "pii_detection_enabled": false, "pii_detection_mask": true, "prompt_injection_detection_enabled": false, "openai_moderation_enabled": false, "openai_moderation_categories": null, "reasoning_tools_enabled": true, "tool_calls_compression": { "enabled": false, "threshold": 3, "instructions": "" } }, "webhook_url": "https://webhook.xpander.ai/?agent_id=&asynchronous=false" } ``` ## Notes * Only `name` is required. All other fields are optional and will use platform defaults. * The `unique_name` is auto-generated as a human-friendly slug (e.g., "jade-bass") * The `webhook_url` is auto-generated for agent invocations * Agent starts in `ACTIVE` status immediately upon creation and is ready for invocation * `version` starts at 2 and increments with each deployment * `has_pending_changes` indicates whether there are unpublished configuration changes * The API may auto-upgrade `model_name` (e.g., requested `gpt-4.1` returns `gpt-5.2`) ## Next Steps After creating an agent: 1. Update instructions using [Update Agent](/api-reference/v1/agents/update-agent) 2. Add tools and knowledge bases to the agent 3. Deploy the agent using [Deploy Agent](/api-reference/v1/agents/deploy-agent) 4. Invoke the agent using the task execution endpoints # Delete Agent Source: https://docs.xpander.ai/api-reference/v1/agents/delete-agent DELETE /v1/agents/{agent_id} Permanently delete an AI agent and all associated resources Permanently delete an agent. This action cannot be undone. ## Path Parameters Unique identifier of the agent to delete (UUID format) ## Response Returns HTTP 202 Accepted with body `null` on successful deletion. ## Example Request ```bash theme={"dark"} curl -X DELETE -H "x-api-key: " \ https://api.xpander.ai/v1/agents/ ``` ## Example Response ``` HTTP/1.1 202 Accepted Content-Type: application/json null ``` The endpoint returns `202 Accepted` to indicate the deletion request has been accepted and will be processed asynchronously. ## Notes * All running tasks for this agent will be cancelled * Agent configuration and execution history will be permanently removed * This action cannot be undone * Associated knowledge bases and tools are not deleted (they remain in your organization) * You can also delete agents through the web dashboard at [https://chat.xpander.ai](https://chat.xpander.ai) * An agent can only be deleted if the `deletable` field is `true` (use [Get Agent](/api-reference/v1/agents/get-agent) to check) # Deploy Agent Source: https://docs.xpander.ai/api-reference/v1/agents/deploy-agent PUT /v1/agents/{agent_id} Deploy an AI agent to make it active and available for task execution Deploy an agent to production. This validates the configuration and makes the agent available for invocation. ## Path Parameters Unique identifier of the agent to deploy (UUID format) ## Response Returns HTTP 200 with the complete agent object (same structure as [Create Agent](/api-reference/v1/agents/create-agent)). Key response fields: * `id`: Agent identifier * `name`: Agent display name * `status`: Updated status (`ACTIVE` or `INACTIVE`) * `deployment_type`: Deployment infrastructure * `model_provider`: AI model provider * `model_name`: Specific model version * `framework`: Agent framework used * `organization_id`: UUID of the organization that owns this agent * `description`: Auto-generated from instructions if not previously set * `has_pending_changes`: Indicates whether there are unpublished changes * `version`: Current version number of the agent ## Example Request ```bash theme={"dark"} curl -X PUT -H "x-api-key: " \ https://api.xpander.ai/v1/agents/ ``` ## Example Response ```json theme={"dark"} { "id": "", "unique_name": "customer-support-agent", "name": "Customer Support Agent", "description": "You are a customer support agent...", "deployment_type": "serverless", "framework": "agno", "status": "ACTIVE", "icon": "🎧", "model_provider": "anthropic", "model_name": "claude-sonnet-4-5-20250929", "organization_id": "", "version": 2, "type": "manager", "has_pending_changes": false, "instructions": { "role": [ "Always greet the customer warmly", "Search the knowledge base before answering", "Escalate billing issues" ], "goal": [ "Resolve customer inquiries on first contact", "Maintain a friendly tone" ], "general": "You are a customer support agent..." } } ``` ## Notes * Agent must have valid instructions and configuration before deployment * Deployment validates all configurations and dependencies * Previously deployed version remains active until new deployment succeeds * Deployment typically completes within seconds * After deploy, `description` is auto-generated from instructions if not previously set * `has_pending_changes` returns to `false` after successful deployment * Check agent status using [List Agents](/api-reference/v1/agents/list-agents) endpoint * An `ACTIVE` status indicates the agent is ready to handle tasks # Export Agent Source: https://docs.xpander.ai/api-reference/v1/agents/export-agent POST /v1/agents/{agent_id}/export Export an AI agent as a reusable template with configuration and knowledge bases Export an agent into a portable template that can be shared across organizations. The template packages all agent components including configuration, tools, sub-agents, and optionally knowledge bases with their documents. ## Path Parameters The unique identifier (UUID) of the agent to export ## Request Body Display name for the template Description of what the template does Emoji icon for the template (e.g., "🎧", "🚀") Controls whether knowledge bases and their document files are included in the export * `true`: Includes all knowledge bases with their documents and files * `false`: Exports only agent configuration without knowledge bases ## Response Returns an `AgentTemplate` object: Unique identifier for the template (UUID) Template display name Template description Emoji icon representing the template UUID of the organization that created the template Complete agent configuration Original agent ID Agent name Agent description Agent instructions (role, goal, general) Array of custom functions Array of connected tools Array of sub-agent definitions Array of knowledge bases (if with\_knowledge\_bases is true) ## Example Request ```bash theme={"dark"} curl -X POST -H "x-api-key: " \ -H "Content-Type: application/json" \ -d '{ "name": "Customer Support Agent Template", "description": "Pre-configured agent for customer support workflows", "icon": "🎧", "with_knowledge_bases": true }' \ https://api.xpander.ai/v1/agents//export ``` ## Example Response ```json theme={"dark"} { "id": "", "name": "Customer Support Agent Template", "description": "Pre-configured agent for customer support workflows", "icon": "🎧", "organization_id": "", "agent_definition": { "id": "", "name": "Customer Support Agent", "description": "Handles customer inquiries and provides support", "instructions": { "role": ["Customer support specialist"], "goal": ["Resolve customer issues efficiently"], "general": "Be helpful and professional" }, "custom_functions": [], "connectors": [ { "name": "Ticket System", "type": "api" } ], "sub_agents": [], "knowledge_bases": [ { "name": "Product Documentation", "description": "Product guides and FAQs" } ] } } ``` ## Use Cases * **Cross-Organization Sharing**: Share agent templates with other organizations * **Backup & Version Control**: Create snapshots of agent configurations * **Standardization**: Distribute pre-built agents across teams * **Reusability**: Create templates for frequently used agent patterns ## Notes * **Cross-Organization Sharing**: Templates can be shared across different organizations - the template ID works universally * **Knowledge Base Size**: When `with_knowledge_bases: true`, the export includes all document content which may result in larger payloads * **Tool Credentials**: Tool configurations are exported without credentials - recipients will need to provide their own API keys * **Template Immutability**: Exported templates are snapshots and won't update if the original agent changes ## See Also * [Import Agent](/api-reference/v1/agents/import-agent) - Create a new agent from a template * [Create Agent](/api-reference/v1/agents/create-agent) - Create a new agent from scratch * [Get Agent](/api-reference/v1/agents/get-agent) - Retrieve agent details # Cancel Queued Message Source: https://docs.xpander.ai/api-reference/v1/agents/gateway/cancel-queued DELETE /v1/agents/{agent_id}/gateway/conversations/{conversation_id}/queue/{message_id} Cancel one pending queued message by id. Removes a single follow-up from the queue using the `message_id` returned by [Send Conversation Message](/api-reference/v1/agents/gateway/send-message). See the [Agent Gateway overview](/api-reference/v1/agents/gateway/overview) for the full conversation model. # Clear Conversation Queue Source: https://docs.xpander.ai/api-reference/v1/agents/gateway/clear-queue DELETE /v1/agents/{agent_id}/gateway/conversations/{conversation_id}/queue Cancel every pending queued message for the conversation. Removes all queued follow-ups. Does not stop a live run; use [Stop Conversation](/api-reference/v1/agents/gateway/stop) for that. See the [Agent Gateway overview](/api-reference/v1/agents/gateway/overview) for the full conversation model. # Drain Conversation Queue Source: https://docs.xpander.ai/api-reference/v1/agents/gateway/drain-stream POST /v1/agents/{agent_id}/gateway/conversations/{conversation_id}/drain/stream Drain an idle conversation's queued follow-ups, streaming each turn over SSE. Opened when a conversation has queued messages but no live run. Streams the same `TaskUpdateEvent` events as invoke. No-op when a live run already owns the drain. See the [Agent Gateway overview](/api-reference/v1/agents/gateway/overview) for the full conversation model. # Edit Message + Re-invoke Source: https://docs.xpander.ai/api-reference/v1/agents/gateway/edit-message POST /v1/agents/{agent_id}/gateway/conversations/{conversation_id}/edit/{message_id} Rewrite a prior user message and re-run the gateway (sync). Trims every entry after the edited message, then re-runs the turn and returns the finalized execution. Preempts any in-flight run on the same conversation. Use the [stream variant](/api-reference/v1/agents/gateway/edit-message-stream) for live events. See the [Agent Gateway overview](/api-reference/v1/agents/gateway/overview) for the full conversation model. # Edit Message + Re-invoke (Stream) Source: https://docs.xpander.ai/api-reference/v1/agents/gateway/edit-message-stream POST /v1/agents/{agent_id}/gateway/conversations/{conversation_id}/edit/{message_id}/stream Stream variant of edit + re-invoke. Same as [Edit Message + Re-invoke](/api-reference/v1/agents/gateway/edit-message) but streams every `TaskUpdateEvent` over SSE instead of returning the finalized execution. See the [Agent Gateway overview](/api-reference/v1/agents/gateway/overview) for the full conversation model. # Get Conversation Source: https://docs.xpander.ai/api-reference/v1/agents/gateway/get-conversation GET /v1/agents/{agent_id}/gateway/conversations/{conversation_id} Fetch a conversation's execution, activity thread, usage, and sub-executions. Returns the parent execution row, the full activity thread, aggregate cost / token usage, and every sub-execution's (execution, activity, usage) triple. See the [Agent Gateway overview](/api-reference/v1/agents/gateway/overview) for the full conversation model. # Agent Gateway Source: https://docs.xpander.ai/api-reference/v1/agents/gateway/overview The multi-turn conversational surface for talking with an agent over a long-lived conversation. The **agent gateway** is the conversational execution surface of the platform. It is the same engine the xpander chat app drives, now exposed on the REST API behind your normal API key (`x-api-key`) or OAuth2 JWT. Where [Invoke Agent](/api-reference/v1/agents/invoke-sync) runs a single one-shot task, the gateway models a **conversation**: a long-lived thread you can send follow-ups to, queue messages against, stop mid-run, edit, and resume from interactive cards. ## Why the gateway Two properties make the gateway the right surface for a chat-style experience: * **Fast time-to-first-token (TTFT).** The gateway is a lightweight router. It streams a `connected` event the instant the request lands, then its router LLM acknowledges and starts answering immediately, before any heavy downstream work begins. You get a first token in roughly one network round-trip instead of waiting for a full agent to spin up and run. * **Effectively unlimited context window.** The router never stuffs the whole conversation into one LLM context. The actual work is delegated to **sub-executions** - each a fresh, bounded agent run - and their results are summarized back into the conversation. Long threads are compacted as they grow, so a conversation can run far longer than any single model's context limit without degrading. The trade-off versus one-shot [invoke](/api-reference/v1/agents/invoke-sync): the gateway optimizes for an interactive, growing conversation; invoke optimizes for a single self-contained task you call and forget. ## Conversation model A conversation is identified by a `conversation_id` (the execution id of its first turn). Within a conversation: * **Run a turn** with [Run Gateway Turn](/api-reference/v1/agents/gateway/run-turn) or its [streaming variant](/api-reference/v1/agents/gateway/run-turn-stream), passing `id` = your `conversation_id` to start or continue the same conversation. The stream path is the fast-first-token entrypoint. * **Send a follow-up** with [Send Conversation Message](/api-reference/v1/agents/gateway/send-message). While a turn is running, the follow-up is **queued**; when idle, the response tells you to start a fresh turn. * **Run-state** ([run-state](/api-reference/v1/agents/gateway/run-state)) is a cheap snapshot you poll to decide what to render: is a turn live, how deep is the queue. * **Drain** ([drain/stream](/api-reference/v1/agents/gateway/drain-stream)) runs the queued follow-ups for an idle conversation, streaming each turn. * **Stop** ([stop](/api-reference/v1/agents/gateway/stop)) cancels the active run; the queue survives unless you clear it. * **Edit** ([edit](/api-reference/v1/agents/gateway/edit-message)) rewrites a prior user message, trims the tail, and re-runs the turn. * **Answer** ([answers](/api-reference/v1/agents/gateway/submit-answers)) resumes a turn that paused on an `ask_user_questions` card. ## How it works: the gateway is a router The agent you talk to through the gateway is a **router**. When you send a message, the gateway's own LLM decides what to do with it: answer inline, ask you a clarifying question, or dispatch the actual work to the **downstream agent** as a separate execution (a **sub-execution**). ```mermaid theme={"dark"} flowchart LR U([You]) -- message --> C[Conversation
parent execution
conversation_id] C -- router LLM decides --> C C -- answer inline --> U C -- sync sub-execution --> S[Downstream agent] C -- async sub-execution --> A[Downstream agent] S -- events stream to root --> C A -. result pushed to root when done .-> C ``` So one conversation (the **parent execution**, keyed by `conversation_id` = "root") can spawn many **sub-executions**, one per task the router dispatches. Each sub-execution is a full agent run with its own id, status, result, and token usage. ### Sub-executions: sync vs async The router picks a mode per task: * **Sync (foreground).** The router drives the downstream agent inline and **streams its events onto the root conversation** as they happen, so you see the child's `tool_call_*`, `chunk`, and `sub_task_finished` events live on the same SSE. The router waits for the child before continuing the turn. * **Async (background).** The router dispatches the task and keeps going without waiting. You get the **sub-execution id** back immediately, so you can query it on its own with [Get Task](/api-reference/v1/tasks/get-task). When it finishes, its **result is pushed to the root** conversation (a `sub_task_finished` event on a live stream, and it appears under the conversation's `sub_executions` on the next [Get Conversation](/api-reference/v1/agents/gateway/get-conversation)). The parent execution tracks its children in `sub_executions` (in-flight) and `finished_sub_executions` (done). Either way the root conversation is the single place that accumulates every result. You can override the router's per-task pick with the `sub_tasks` query parameter on [Run Gateway Turn](/api-reference/v1/agents/gateway/run-turn) and its [streaming variant](/api-reference/v1/agents/gateway/run-turn-stream): `sync` forces every sub-execution to run in the foreground, `async` forces every sub-execution to the background, and `auto` returns the conversation to the computed per-task decision. The mode sticks to the conversation until you pass a different value. ## Sending messages while a turn runs (the queue) A conversation runs **one turn at a time**. If you send a follow-up while a turn is still running, it does not interrupt or run in parallel - it goes into the conversation's **queue** and runs as the next turn once the current one finishes. [Send Conversation Message](/api-reference/v1/agents/gateway/send-message) takes a `mode`: * `mode=auto` (default): queue the message if a turn is running; if the conversation is idle, the response is `started`, meaning you should run the turn yourself with [Run Gateway Turn](/api-reference/v1/agents/gateway/run-turn-stream) (`id` = `conversation_id`). * `mode=queue`: always enqueue, even if idle. The response is `{ action, message_id, queue_depth }` - `queued` with the new depth, or `started` when idle. ```mermaid theme={"dark"} sequenceDiagram participant C as Client participant Conv as Conversation (root) C->>Conv: invoke (id = conversation_id), SSE open, turn running C->>Conv: POST /messages (follow-up while running) Conv-->>C: 200 { action: "queued", queue_depth: 1 } Note over Conv: current turn finishes Conv-->>C: gateway_queue_updated (drain) then the next turn's events Note over Conv: drains the queue in order until empty ``` How queued messages actually run: * If a **live stream** is attached (the turn that was running has an open SSE), it drains the queue itself: when the turn finishes it pops the next message and runs it as the following turn on the **same** stream. Each drain is announced with a `gateway_queue_updated` event (`last_action: "drain"`). * If **nothing** is holding a stream (you queued over plain REST then disconnected, or queued while idle), call [Drain Queue](/api-reference/v1/agents/gateway/drain-stream) to run the pending messages and stream them. A background reaper is the backstop: it resumes a conversation whose queue is non-empty but has no live run. Manage the queue with [Run State](/api-reference/v1/agents/gateway/run-state) (current `queue_depth` + previews), [Cancel Queued Message](/api-reference/v1/agents/gateway/cancel-queued) (drop one), and [Clear Queue](/api-reference/v1/agents/gateway/clear-queue) (drop all). [Stop](/api-reference/v1/agents/gateway/stop) cancels the running turn and, by default, keeps the queue. ## Getting results There are three ways to read what an agent produced, depending on how you called it: 1. **From the stream.** On any streaming endpoint, the terminal `task_finished` event carries the finalized execution, including its `result`. Foreground sub-task results also arrive on the stream as `sub_task_finished` events. 2. **Poll the conversation.** Call [Get Conversation](/api-reference/v1/agents/gateway/get-conversation) at any time. It returns the parent execution (with `status` and `result`), the full activity thread, aggregate token usage, and **every sub-execution's own `(execution, activity, usage)` triple** - so a single call gives you the downstream agents' results too. 3. **Poll the task directly.** Every execution id (the `conversation_id` and each sub-execution id) is a task. Use [Get Task](/api-reference/v1/tasks/get-task) to fetch one execution's status + result, or [Get Task Thread](/api-reference/v1/tasks/get-thread) for its activity log. ### Without holding a stream For a request/response integration that doesn't keep an SSE open: 1. Run the turn with [Run Gateway Turn](/api-reference/v1/agents/gateway/run-turn) (sync). It blocks until the turn completes and returns the execution with its `result`. 2. Add follow-ups with [Send Conversation Message](/api-reference/v1/agents/gateway/send-message) using `mode=queue`, then run them with [Drain Queue](/api-reference/v1/agents/gateway/drain-stream) (a background reaper also picks up an orphaned queue). 3. Check progress any time with [Run State](/api-reference/v1/agents/gateway/run-state) (`is_running`, `queue_depth`) or [Get Task](/api-reference/v1/tasks/get-task) on the `conversation_id` (status `completed` / `failed` / `stopped`), and read results with [Get Conversation](/api-reference/v1/agents/gateway/get-conversation) (parent `result` plus each sub-execution's `result`). ## Streaming The streaming endpoints ([run a turn](/api-reference/v1/agents/gateway/run-turn-stream), drain, answers, edit-stream) return **Server-Sent Events**. The stream opens with a `connected` event (fast first byte), then each `data:` line is a JSON `TaskUpdateEvent` (`task_created`, `chunk`, `tool_call_request`, `sub_task_created`, `sub_task_finished`, `task_finished`, and so on) - the same event shape as [Invoke Agent (Stream)](/api-reference/v1/agents/invoke-stream). ## Auth and identity Every route is agent-scoped and authorized by your API key's access to that agent, exactly like the rest of the v1 API. There is no end-user session, so message and answer bodies accept an optional `user` object if you want to attribute the turn to a specific person; if you omit it, the turn runs without an attributed end-user (continuations keep whatever user the conversation already carries). # Conversation Run State Source: https://docs.xpander.ai/api-reference/v1/agents/gateway/run-state GET /v1/agents/{agent_id}/gateway/conversations/{conversation_id}/run-state Cheap snapshot of a conversation's run and queue state. Poll this to see whether a turn is live and how many follow-ups are queued (with previews). It is Redis-backed and cheap, so it is safe to poll frequently. See the [Agent Gateway overview](/api-reference/v1/agents/gateway/overview) for the full conversation model. # Run Gateway Turn Source: https://docs.xpander.ai/api-reference/v1/agents/gateway/run-turn POST /v1/agents/{agent_id}/gateway/invoke Run a gateway turn and wait for the finalized execution. Run a turn through the gateway and block until it finishes, returning the completed execution with its `result`. Pass `id` = your `conversation_id` to start or continue a conversation; omit it to start a new one (the returned execution's id becomes the `conversation_id`). Re-invoking a conversation that is already running preempts the in-flight turn. Use the `sub_tasks` query parameter to force how the router dispatches downstream work: `sync` runs every sub-execution in the foreground (the turn waits for each child, like the email trigger), `async` pushes every sub-execution to the background (results are pushed back to the conversation later), and `auto` restores the computed per-task decision. This is separate from whether this API call blocks, and the mode sticks to the conversation until changed. For fast time-to-first-token and live progress, prefer the [streaming variant](/api-reference/v1/agents/gateway/run-turn-stream). See the [Agent Gateway overview](/api-reference/v1/agents/gateway/overview) for the full conversation model. # Run Gateway Turn (Stream) Source: https://docs.xpander.ai/api-reference/v1/agents/gateway/run-turn-stream POST /v1/agents/{agent_id}/gateway/invoke/stream Run a gateway turn and stream every event over SSE. Run a turn through the gateway and stream every `TaskUpdateEvent` over Server-Sent Events. This is the fast-time-to-first-token path: a `connected` event flushes immediately, then the router starts answering before any heavy downstream work begins. Pass `id` = your `conversation_id` to start or continue a conversation; omit it to start a new one. Sub-execution events (the downstream agents the router dispatches) are forwarded onto the same stream. Use the `sub_tasks` query parameter to force how the router dispatches downstream work: `sync` runs every sub-execution in the foreground (the turn waits for each child, like the email trigger), `async` pushes every sub-execution to the background (results are pushed back to the conversation later), and `auto` restores the computed per-task decision. This is separate from whether this API call blocks, and the mode sticks to the conversation until changed. See the [Agent Gateway overview](/api-reference/v1/agents/gateway/overview) for the event model and how sub-executions stream back. # Send Conversation Message Source: https://docs.xpander.ai/api-reference/v1/agents/gateway/send-message POST /v1/agents/{agent_id}/gateway/conversations/{conversation_id}/messages Send a follow-up to a (possibly running) conversation. `mode=auto` queues the message while a turn is running and signals `started` when the conversation is idle; `mode=queue` always enqueues. A `started` response means the message was **not** enqueued (`queue_depth: 0`) - the conversation is idle, so run the turn yourself with [Run Gateway Turn](/api-reference/v1/agents/gateway/run-turn) passing `id` = `conversation_id`. A `queued` response means it was enqueued behind a running turn; that turn drains it automatically, or if nothing is streaming you run the queue with [Drain Queue](/api-reference/v1/agents/gateway/drain-stream). See the [Agent Gateway overview](/api-reference/v1/agents/gateway/overview) for the full conversation model. # Stop Conversation Source: https://docs.xpander.ai/api-reference/v1/agents/gateway/stop POST /v1/agents/{agent_id}/gateway/conversations/{conversation_id}/stop Cancel the active run for a conversation. Cancels the in-flight turn (router plus any child sub-execution). The queue is kept unless `clear_queue=true`. See the [Agent Gateway overview](/api-reference/v1/agents/gateway/overview) for the full conversation model. # Submit Question Answers Source: https://docs.xpander.ai/api-reference/v1/agents/gateway/submit-answers POST /v1/agents/{agent_id}/gateway/conversations/{conversation_id}/answers Answer a prior ask_user_questions card and resume the turn (SSE). When a turn pauses with an `ask_user_questions` card, submit the structured answers here to resume. Answers are validated against the asked questions; a mismatch returns `400` before any run. Streams the resumed turn's events over SSE. See the [Agent Gateway overview](/api-reference/v1/agents/gateway/overview) for the full conversation model. # Get Agent Source: https://docs.xpander.ai/api-reference/v1/agents/get-agent GET /v1/agents/{agent_id} Retrieve an agent in a simplified view — its attached tools as one flat list, plus core configuration. Returns a **simplified agent view**. Instead of the low-level `graph`, `attached_tools`, `oas`, and fully-resolved tool schemas, the agent's tools are surfaced as one flat `tools` array (see the `AgentTool` shape below). Use the [Tools API](/api-reference/v1/tools/list-tools) to add or remove tools. ## Path Parameters Unique identifier of the agent (UUID format) ## Response Agent UUID Display name What the agent does (auto-generated on deploy from `instructions`) Emoji icon (e.g., `🚀`) Agent type (e.g., `regular`, `manager`) `ACTIVE` (deployed) or `INACTIVE` LLM provider (e.g., `anthropic`) LLM model (e.g., `claude-sonnet-4-6`) Role statements Goals Free-form general instructions IDs of attached knowledge bases Trigger source types (e.g., `sdk`, `webhook`, `slack`) The agent's attached tools, unified across kinds. Each item is an `AgentTool`: Stable handle for this attached tool. Pass it to [Remove Agent Tool](/api-reference/v1/agents/tools/remove-agent-tool). One of `action`, `custom_function`, `mcp`, `agent`, `workflow`. Human-readable tool name. Connector connection id. `action` only. Operation catalog id. `action` only. OpenAPI operationId. `action` only. Custom function id. `custom_function` only. MCP registry id. `mcp` only. Subset of MCP tools exposed. `mcp` only. Referenced sub-agent or workflow id. `agent` / `workflow` only. ISO 8601 creation timestamp UUID of the creating user Resolved creator details (`null` when unavailable — null-check before reading). User UUID Display name (falls back to email/id) User email # Get Agent Inbox Source: https://docs.xpander.ai/api-reference/v1/agents/get-agent-inbox GET /v1/agents/{agent_id}/inbox List the conversations that reached an agent by email or WhatsApp Agents can be reached on inbound channels: email (when an email trigger is configured) and WhatsApp (on a user's personal Omni). This endpoint lists those conversations - the agent's inbox - newest first, with filters for channel, date range and title text. It is agent-wide: every sender's conversation with this agent, not just the caller's. For an agent's full task history across all sources, use [Get Agent Tasks](/api-reference/v1/agents/get-agent-tasks) instead. ## Path Parameters Unique identifier of the agent (UUID format) ## Query Parameters Comma-separated channels to include: `email`, `whatsapp`. Defaults to every channel enabled on the agent. Asking for a channel the agent does not have returns `400`. Only conversations created at or after this ISO date/datetime. A bare date (`2026-08-01`) covers that whole UTC day. Only conversations created at or before this ISO date/datetime. A bare date covers the whole day. Case-insensitive text matched against conversation titles. Maximum conversations to return (1-50). ## Response Inbound conversations, newest first Conversation (task) id - pass it to [Get Task Thread](/api-reference/v1/tasks/get-thread) to read the messages Inbound channel: `email` or `whatsapp` Conversation title Execution status: `pending`, `executing`, `paused`, `error`, `failed`, `completed`, or `stopped` Profile id or address of whoever started the conversation (nullable) Sender email address, resolved from the profile when the row carries an id (nullable) ISO timestamp of the first message ISO timestamp of the last update Inbound channels enabled on this agent. An empty array means the agent has no inbox at all - clients should hide the surface rather than show an empty list. Number of matching conversations before `limit` was applied ## Example Requests ### Everything in the inbox ```bash theme={"dark"} curl -X GET -H "x-api-key: " \ "https://api.xpander.ai/v1/agents//inbox" ``` ### Search one channel ```bash theme={"dark"} curl -X GET -H "x-api-key: " \ "https://api.xpander.ai/v1/agents//inbox?source=email&q=invoice&limit=10" ``` ### A date range ```bash theme={"dark"} curl -X GET -H "x-api-key: " \ "https://api.xpander.ai/v1/agents//inbox?from_date=2026-08-01&to_date=2026-08-03" ``` ## Example Response ```json theme={"dark"} { "items": [ { "id": "df716857-0c93-4ec9-9b91-bbe1b9879b59", "source": "email", "title": "Invoice question", "status": "completed", "user_id": "92310d0c-feda-4e8d-82df-a5320247b10b", "sender": "dan@acme.com", "created_at": "2026-08-03T07:41:12.426253Z", "updated_at": "2026-08-03T07:41:44.108221Z" } ], "sources_enabled": ["email"], "total": 1 } ``` ## Use Cases * **Inbox view**: render everything people sent an agent, across channels * **Lookup**: find the conversation a specific person or subject started * **Triage**: filter by date range to review what arrived while nobody was watching ## Notes * Only top-level conversations are listed; sub-tasks spawned inside a conversation are excluded * Each channel is queried separately and the results merged, so a channel that is temporarily unavailable degrades the list rather than failing it - the request only errors when every requested channel fails * `sender` is null when the conversation came from an identity with no email on file * The agent itself can list the same conversations in chat, so "what emails did you get?" is answered from real data rather than guessed ## See Also * [Get Agent Tasks](/api-reference/v1/agents/get-agent-tasks) - all tasks for an agent, any source * [Get Task Thread](/api-reference/v1/tasks/get-thread) - the messages inside one conversation * [List Tasks](/api-reference/v1/tasks/list-tasks) - tasks across all agents # Get Agent Tasks Source: https://docs.xpander.ai/api-reference/v1/agents/get-agent-tasks GET /v1/agents/{agent_id}/tasks Retrieve paginated list of task executions for a specific agent with optional filters Get paginated task records for a specific agent with support for filtering by user, status, and parent task relationships. In multi-turn conversations, reusing an invocation `id` updates the same task/thread record instead of creating a brand-new top-level item for every turn. ## Path Parameters Unique identifier of the agent (UUID format) ## Query Parameters Page number (starting from 1) Items per page (maximum 50) Filter by user ID who created the task Filter by parent task ID (for sub-tasks) Filter by triggering agent ID (parent calling agent in multi-agent workflows) Filter by task execution status: `pending`, `executing`, `paused`, `error`, `failed`, `completed`, `stopped` Filter by internal task processing status ## Response Array of task objects Unique identifier for the task (UUID format) ID of the agent that executed this task ID of the user who created the task (nullable) ID of parent task if this is a subtask (nullable) ID of agent that triggered this task (nullable) Organization UUID this task belongs to Current task status: `pending`, `executing`, `paused`, `error`, `failed`, `completed`, or `stopped` Source of task invocation: sdk, webhook, assistant, etc. ISO timestamp of task creation ISO timestamp of last update Task title or the latest input text for that task/thread Latest result for that task/thread (nullable, present when completed) Total number of tasks for this agent Current page number Number of items per page Total number of pages available ## Example Requests ### List all tasks for an agent ```bash theme={"dark"} curl -X GET -H "x-api-key: " \ "https://api.xpander.ai/v1/agents//tasks?page=1&per_page=2" ``` ### Filter by status ```bash theme={"dark"} curl -X GET -H "x-api-key: " \ "https://api.xpander.ai/v1/agents//tasks?status=completed&page=1&per_page=10" ``` ### Filter by user ```bash theme={"dark"} curl -X GET -H "x-api-key: " \ "https://api.xpander.ai/v1/agents//tasks?user_id=&page=1&per_page=10" ``` ## Example Response ```json theme={"dark"} { "items": [ { "id": "fbd08e4d-cfa7-4838-b6e6-e51855ac2ba3", "agent_id": "", "user_id": null, "parent_task_id": null, "triggering_agent_id": null, "organization_id": "", "status": "completed", "source_node_type": "sdk", "created_at": "2026-03-23T00:45:24.296117Z", "updated_at": "2026-03-23T00:45:31.040146Z", "title": "Reply with exactly SECOND", "result": "SECOND" } ], "total": 6, "page": 1, "per_page": 5, "total_pages": 2 } ``` ## Use Cases * **Monitor Agent Activity**: Track all tasks executed by a specific agent * **Debug Workflows**: Filter by parent\_task\_id to see sub-task hierarchies * **User Analytics**: Filter by user\_id to see tasks from specific users * **Multi-Agent Debugging**: Use triggering\_agent\_id to trace agent-to-agent delegations * **Performance Analysis**: Track task completion times and status distribution ## Notes * Tasks are returned in reverse chronological order (newest first) * Continuing a conversation by sending the same invocation `id` updates the same task/thread record instead of creating a new top-level task item * The `title`, `result`, and `updated_at` fields reflect the latest turn for that task/thread * The `source_node_type` indicates how the task was invoked (SDK, webhook, web UI, etc.) * Sub-tasks (when `parent_task_id` is set) represent work delegated to other agents * Use [Get Task](/api-reference/v1/tasks/get-task) for the latest full task object and [Get Task Thread](/api-reference/v1/tasks/get-thread) or [Get Task Thread (Full)](/api-reference/v1/tasks/get-thread-full) for message history ## See Also * [List Tasks](/api-reference/v1/tasks/list-tasks) - List all tasks across all agents * [Get Task](/api-reference/v1/tasks/get-task) - Get detailed information about a specific task * [Invoke Agent](/api-reference/v1/agents/invoke-async) - Create new tasks # Import Agent Source: https://docs.xpander.ai/api-reference/v1/agents/import-agent POST /v1/agents/template_import/{template_id} Import an AI agent from a template and create a new agent instance Create a new agent instance from a template. The template can be from your organization or shared from another organization. All agent configuration, tools, sub-agents, and optionally knowledge bases will be replicated into your organization. ## Path Parameters Unique identifier of the template to import (UUID format) ## Request Body Display name for the new agent instance Description of the agent instance (optional - can customize the template description) Emoji icon for the agent (optional - defaults to template icon) Controls whether to import knowledge bases from the template * `true`: Imports all knowledge bases with their documents and files (if included in template) * `false`: Imports only agent configuration without knowledge bases ## Response Returns a complete `AIAgent` object: Unique identifier for the created agent (UUID) Display name of the agent Agent description Emoji icon representing the agent Current deployment status: `ACTIVE` or `INACTIVE` UUID of the template this agent was imported from Deployment infrastructure: `serverless` UUID of your organization System instructions configuration inherited from template Array of role descriptions Array of goal descriptions General instructions text AI model provider (e.g., `openai`) Specific model version (e.g., `gpt-4o`, `gpt-4.1`) Agent framework used (e.g., `agno`) Array of imported knowledge bases (if `with_knowledge_bases: true`) ISO 8601 timestamp of when the agent was created ## Example Requests ### Basic Import ```bash theme={"dark"} curl -X POST -H "x-api-key: " \ -H "Content-Type: application/json" \ -d '{ "name": "My Support Agent", "description": "Customer support agent from template", "icon": "🎧", "with_knowledge_bases": true }' \ https://api.xpander.ai/v1/agents/template_import/ ``` ### Import Without Knowledge Bases ```bash theme={"dark"} curl -X POST -H "x-api-key: " \ -H "Content-Type: application/json" \ -d '{ "name": "Support Agent Framework", "description": "Will add custom knowledge bases later", "with_knowledge_bases": false }' \ https://api.xpander.ai/v1/agents/template_import/ ``` ## Example Response ```json theme={"dark"} { "id": "", "name": "My Support Agent", "description": "Customer support agent from template", "icon": "🎧", "status": "ACTIVE", "origin_template": "", "organization_id": "", "deployment_type": "serverless", "created_at": "2026-02-07T10:30:00.000000Z", "instructions": { "role": ["Customer support specialist"], "goal": ["Resolve customer issues efficiently"], "general": "Be helpful and professional" }, "model_provider": "openai", "model_name": "gpt-4.1", "framework": "agno", "knowledge_bases": [ { "id": "", "name": "Product Documentation", "description": "Product guides and FAQs" } ], "tools": [], "graph": [] } ``` ## Import Behavior When importing a template: 1. **New Agent Created**: A completely independent agent instance is created in your organization 2. **Configuration Copied**: All agent settings, instructions, and behavior are replicated 3. **Sub-Agents Recreated**: Complete agent hierarchy is maintained with new instances 4. **Knowledge Bases**: Documents are copied to your organization (if included and `with_knowledge_bases: true`) 5. **Tools & Connectors**: Tool configurations are preserved - you'll need to provide credentials 6. **Independence**: Changes to the imported agent won't affect the source agent or template ## Notes * **Cross-Organization Support**: Templates can be imported from any organization - share the template ID * **Customization**: You can modify the agent name, description, and icon during import * **Tool Setup**: After import, configure credentials for any tools that require authentication * **Knowledge Bases**: If the template was exported without knowledge bases, `with_knowledge_bases: true` has no effect * **Origin Tracking**: The `origin_template` field tracks which template was used for import ## Next Steps After importing an agent: 1. Update agent configuration using [Update Agent](/api-reference/v1/agents/update-agent) if needed 2. Configure tool credentials if the agent uses external tools 3. Deploy the agent using [Deploy Agent](/api-reference/v1/agents/deploy-agent) 4. Test the agent with sample tasks ## See Also * [Export Agent](/api-reference/v1/agents/export-agent) - Create a template from an existing agent * [Create Agent](/api-reference/v1/agents/create-agent) - Create a new agent from scratch * [Update Agent](/api-reference/v1/agents/update-agent) - Customize the imported agent * [Deploy Agent](/api-reference/v1/agents/deploy-agent) - Deploy the imported agent # Invoke Agent (Async) Source: https://docs.xpander.ai/api-reference/v1/agents/invoke-async POST /v1/agents/{agent_id}/invoke/async Execute an agent asynchronously. Returns immediately with a task ID for polling. Invoke an agent asynchronously. Returns immediately with a task ID and `status: "pending"`. Poll the [Get Task](/api-reference/v1/tasks/get-task) endpoint to check when results are ready. Use this for long-running tasks, background processing, or when you don't want to block a request. ## Path Parameters Agent ID (UUID) ## Request Body The request body is identical to [Invoke Agent (Sync)](/api-reference/v1/agents/invoke-sync). * `input.text` is required * `input.user.id` is required * `input.user.email` is required * `user_oidc_token` is optional for MCP OAuth-backed tools The message or prompt to send to the agent. End user identity. External user ID from your system. User email address. Optional OIDC token for MCP OAuth-authenticated tools. Thread ID for multi-turn conversations. Pass the `id` from a previous task to continue the conversation. When `true`, files in `input.files` are not injected into the LLM context window. See [Invoke Sync: Processing Files](/api-reference/v1/agents/invoke-sync#processing-files). `default` or `harder`. Controls reasoning depth. Additional instructions appended to the system prompt for this invocation only. Extra context appended to the agent's system prompt **for this invocation only**. Unlike `instructions_override` (which adds behavioral instructions), this supplies supplementary facts or context the agent should consider for this run — e.g. relevant background data, the current state of an external system, or a user's recent activity. Natural-language description of desired output Per-execution LLM provider override. See [Invoke Sync: Per-Execution LLM Override](/api-reference/v1/agents/invoke-sync#per-execution-llm-override). Per-execution model override. See [Invoke Sync: Per-Execution LLM Override](/api-reference/v1/agents/invoke-sync#per-execution-llm-override). Per-execution reasoning-effort override (`low` | `medium` | `high` | `xhigh`). See [Invoke Sync: Per-Execution LLM Override](/api-reference/v1/agents/invoke-sync#per-execution-llm-override). ## Query Parameters Agent version to invoke. Defaults to latest deployed. Use `"draft"` to test undeployed changes. ## Response Returns immediately with the task object in `pending` state. Task ID — use this to poll for results via [Get Task](/api-reference/v1/tasks/get-task) Always `pending` on initial return. Transitions to `executing` → `completed` (or `failed`/`error`). `null` until the task completes ## Basic Example ```bash theme={"dark"} curl -s -X POST "https://api.xpander.ai/v1/agents//invoke/async" \ -H "Content-Type: application/json" \ -H "x-api-key: " \ -d '{"input": {"text": "Analyze competitor pricing for Q1 2026"}}' ``` Response (immediate): ```json theme={"dark"} { "id": "81250b20-e9d7-4b3b-9995-07dc72b4bb59", "agent_id": "", "status": "pending", "result": null, "created_at": "2026-02-07T02:13:26.325626Z" } ``` ## Polling for Results ```bash theme={"dark"} # 1. Start the async task TASK_ID=$(curl -s -X POST "https://api.xpander.ai/v1/agents//invoke/async" \ -H "Content-Type: application/json" \ -H "x-api-key: " \ -d '{"input": {"text": "Generate a market report"}}' | jq -r '.id') echo "Task started: $TASK_ID" # 2. Poll until done while true; do RESPONSE=$(curl -s "https://api.xpander.ai/v1/tasks/$TASK_ID" \ -H "x-api-key: ") STATUS=$(echo "$RESPONSE" | jq -r '.status') echo "Status: $STATUS" if [ "$STATUS" = "completed" ] || [ "$STATUS" = "failed" ] || [ "$STATUS" = "error" ]; then echo "$RESPONSE" | jq -r '.result' break fi sleep 2 done ``` ## Example Response (After Completion) Poll the task after it finishes to get the full result: ```json theme={"dark"} { "id": "81250b20-e9d7-4b3b-9995-07dc72b4bb59", "agent_id": "", "status": "completed", "input": { "text": "Analyze competitor pricing for Q1 2026", "user": null }, "result": "Based on my analysis, the three main competitors...", "created_at": "2026-02-07T02:13:26.325626Z", "finished_at": "2026-02-07T02:13:41.897000Z", "source": "api" } ``` ## Task Status Flow `pending` → `executing` → `completed` | `failed` | `error` | `stopped` For multi-turn conversations, always wait for a task to reach `completed` before sending the next message with the same `id`. Sending a follow-up while the previous task is still `executing` may cause unexpected behavior. ## See Also * [Invoke Agent (Sync)](/api-reference/v1/agents/invoke-sync) — blocks until completion (best for quick tasks) * [Invoke Agent (Stream)](/api-reference/v1/agents/invoke-stream) — real-time SSE stream * [Get Task](/api-reference/v1/tasks/get-task) — poll for task status and results * [Webhook documentation](/guides/deploy/webhooks) — get notified when tasks complete instead of polling # Invoke Agent (Stream) Source: https://docs.xpander.ai/api-reference/v1/agents/invoke-stream POST /v1/agents/{agent_id}/invoke/stream Execute an agent with real-time Server-Sent Events (SSE). Reusing `id` continues the same task/thread. Invoke an agent with real-time streaming via Server-Sent Events (SSE). Events fire as the agent works, so you can render progress, chunks, tool activity, and the final result in an interactive UI. ## Path Parameters Agent ID (UUID) ## Request Body The request body is identical to [Invoke Agent (Sync)](/api-reference/v1/agents/invoke-sync). Only `input.text` is required. The message or prompt to send to the agent. URLs of files for the agent to process. For large files, set `disable_attachment_injection: true`. End user identity. See [Invoke Sync docs](/api-reference/v1/agents/invoke-sync#with-user-identity) for the full `user` object schema. Task/thread ID for multi-turn conversations. Pass the `id` from a previous task response to continue the same conversation. Continued turns keep using that same ID. When `true`, files in `input.files` are not injected into the LLM context window. See [Invoke Sync: Processing Files](/api-reference/v1/agents/invoke-sync#processing-files). `default` or `harder`. Controls reasoning depth. Additional instructions appended to the system prompt for this invocation only. Extra context appended to the agent's system prompt **for this invocation only**. Unlike `instructions_override` (which adds behavioral instructions), this supplies supplementary facts or context the agent should consider for this run — e.g. relevant background data, the current state of an external system, or a user's recent activity. Natural-language description of desired output Per-execution LLM provider override. See [Invoke Sync: Per-Execution LLM Override](/api-reference/v1/agents/invoke-sync#per-execution-llm-override). Per-execution model override. See [Invoke Sync: Per-Execution LLM Override](/api-reference/v1/agents/invoke-sync#per-execution-llm-override). Per-execution reasoning-effort override (`low` | `medium` | `high` | `xhigh`). See [Invoke Sync: Per-Execution LLM Override](/api-reference/v1/agents/invoke-sync#per-execution-llm-override). ## Query Parameters Agent version to invoke. Defaults to latest deployed. Use `"draft"` to test undeployed changes. ## Response Format Returns `Content-Type: text/event-stream`. Each SSE line is prefixed with `data: ` and contains a JSON object with this top-level shape: ```json theme={"dark"} { "type": "task_created | task_updated | chunk | task_finished | ...", "task_id": "", "organization_id": "", "time": "2026-03-23T00:46:03.782693Z", "data": {} } ``` For `chunk` events, `data` is a string fragment. For task lifecycle events, `data` is the task object snapshot at that moment. If you continue a conversation by sending `id: ""`, the stream keeps emitting that same `task_id`. Use [Get Task](/api-reference/v1/tasks/get-task) for the latest turn state and [Get Task Thread](/api-reference/v1/tasks/get-thread) or [Get Task Thread (Full)](/api-reference/v1/tasks/get-thread-full) for the full message history. ## Event Types Events are emitted in this order during a typical invocation: Fired immediately. Contains the task object with `status: "pending"`. This is emitted for both brand-new threads and follow-up turns on an existing task/thread ID. Fired when the task status changes, usually to `executing`. Contains the updated task object. Agent's internal reasoning step. Contains the thought process as a string. Agent's analysis step before tool selection. Agent is calling a tool. Contains tool name, parameters, and reasoning. Tool returned a result. Contains the output from the tool. A piece of the agent's final response. Accumulate these to build the full result. ```json theme={"dark"} {"type": "chunk", "task_id": "...", "data": "partial response text..."} ``` Task is done. Contains the final task object with `status`, `result`, and `finished_at`. A sub-agent was triggered (multi-agent workflows). Deep planning step was updated (when `deep_planning` is enabled on the agent). MCP connector requires authentication. Contains an auth URL the user must visit. ## Basic Example ```bash theme={"dark"} curl -s --no-buffer -X POST "https://api.xpander.ai/v1/agents//invoke/stream" \ -H "Content-Type: application/json" \ -H "x-api-key: " \ -d '{"input": {"text": "Say hello in 5 words"}}' ``` Use `--no-buffer` (or `-N`) for real-time output. ## Real Event Stream Here's what the actual SSE output looks like from a live invocation: ``` data: {"type":"task_created","task_id":"81c63a62-96f9-47bf-818c-8a0a3e4b6ec8","organization_id":"","time":"2026-03-23T00:46:03.782693Z","data":{"id":"81c63a62-96f9-47bf-818c-8a0a3e4b6ec8","agent_id":"","input":{"text":"Reply with exactly RAW","files":[]},"status":"pending","source":"api","output_format":"markdown","events_streaming":true}} data: {"type":"task_updated","task_id":"81c63a62-96f9-47bf-818c-8a0a3e4b6ec8","organization_id":"","time":"2026-03-23T00:46:04.419449Z","data":{"id":"81c63a62-96f9-47bf-818c-8a0a3e4b6ec8","status":"executing",...}} data: {"type":"chunk","task_id":"81c63a62-96f9-47bf-818c-8a0a3e4b6ec8","organization_id":"","time":"2026-03-23T00:46:06.316302Z","data":"RAW"} data: {"type":"task_finished","task_id":"81c63a62-96f9-47bf-818c-8a0a3e4b6ec8","organization_id":"","time":"2026-03-23T00:46:06.797966Z","data":{"id":"81c63a62-96f9-47bf-818c-8a0a3e4b6ec8","status":"completed","result":"RAW","finished_at":"2026-03-23T00:46:06.752706Z",...}} ``` ## Consuming the Stream (Node.js) ```javascript theme={"dark"} const response = await fetch( 'https://api.xpander.ai/v1/agents//invoke/stream', { method: 'POST', headers: { 'x-api-key': '', 'Content-Type': 'application/json' }, body: JSON.stringify({ input: { text: 'Your task here' } }) } ); const reader = response.body.getReader(); const decoder = new TextDecoder(); while (true) { const { done, value } = await reader.read(); if (done) break; const lines = decoder.decode(value).split('\n'); for (const line of lines) { if (!line.startsWith('data: ')) continue; const event = JSON.parse(line.slice(6)); switch (event.type) { case 'chunk': // Stream text to UI as it arrives process.stdout.write(event.data); break; case 'tool_call_request': console.log(`\n[Tool: ${event.data?.tool_name}]`); break; case 'task_finished': console.log('\n\nDone:', event.data.result); break; } } } ``` ## Consuming the Stream (Python) ```python theme={"dark"} import requests import json response = requests.post( 'https://api.xpander.ai/v1/agents//invoke/stream', json={'input': {'text': 'Your task here'}}, headers={ 'x-api-key': '', 'Content-Type': 'application/json' }, stream=True ) for line in response.iter_lines(): if not line: continue line = line.decode('utf-8') if not line.startswith('data: '): continue event = json.loads(line[6:]) if event['type'] == 'chunk': print(event['data'], end='', flush=True) elif event['type'] == 'tool_call_request': print(f"\n[Calling tool: {event['data'].get('tool_name', 'unknown')}]") elif event['type'] == 'task_finished': print(f"\n\nDone. Status: {event['data']['status']}") ``` ## Notes * Use `curl --no-buffer` or `curl -N` for real-time terminal output * The stream ends after the `task_finished` event — close the connection at that point * `chunk` events contain raw text fragments; concatenate them for the full response * `tool_call_request` and `tool_call_result` events let you show tool usage in your UI * `think` and `analyze` events show the agent's reasoning (useful for debugging and transparency) * For multi-turn conversations, wait for `task_finished` before sending the next message with the same `id` * Reusing `id` continues the same task/thread; it does not mint a new top-level task ID for the follow-up turn * [Get Task](/api-reference/v1/tasks/get-task) shows the latest turn state for that ID, while [Get Task Thread](/api-reference/v1/tasks/get-thread) and [Get Task Thread (Full)](/api-reference/v1/tasks/get-thread-full) show the accumulated conversation ## See Also * [Invoke Agent (Sync)](/api-reference/v1/agents/invoke-sync) — blocks until completion * [Invoke Agent (Async)](/api-reference/v1/agents/invoke-async) — returns task ID for polling * [Get Thread](/api-reference/v1/tasks/get-thread) — retrieve conversation history after streaming # Invoke Agent (Sync) Source: https://docs.xpander.ai/api-reference/v1/agents/invoke-sync POST /v1/agents/{agent_id}/invoke Execute an agent and wait for completion. Returns the final result. Invoke an agent synchronously. The request blocks until the agent finishes (typically 5–30 seconds) and returns the completed task with the result. For longer-running tasks, use [Invoke Agent (Async)](/api-reference/v1/agents/invoke-async) or [Invoke Agent (Stream)](/api-reference/v1/agents/invoke-stream). ## Path Parameters Agent ID (UUID) ## Request Body `input.text`, `input.user.id`, and `input.user.email` are required. `user_oidc_token` is optional for MCP OAuth-backed tools. The message or prompt to send to the agent. Identity of the end user invoking the agent. External user ID from your system. User email address. Optional OIDC token for MCP OAuth-authenticated tools. **Thread ID for multi-turn conversations.** Pass the `id` from a previous task's response to continue the same conversation. The agent will have full context of all prior messages. If omitted, a new thread is created automatically. When `true`, files passed in `input.files` are **not injected into the LLM context window**. The file URLs are still available to the agent's tools, but the raw content won't be prepended to the prompt. **Use this when:** * Files are large (would exceed the model's context limit) * You want tools to process the files rather than the LLM reading them directly * You're passing many files and don't need them all in context **Default (`false`):** file contents are downloaded, extracted, and injected directly into the LLM prompt as context. Controls the agent's reasoning depth. `default` for standard reasoning, `harder` for deeper chain-of-thought analysis. Use `harder` for complex multi-step tasks that benefit from more deliberate planning. Additional instructions appended to the agent's system prompt **for this invocation only**. Use this to adjust behavior per-request without changing the agent's configuration — for example, restricting output format, adding constraints, or changing tone. Extra context appended to the agent's system prompt **for this invocation only**. Unlike `instructions_override` (which adds behavioral instructions), this supplies supplementary facts or context the agent should consider for this run — e.g. relevant background data, the current state of an external system, or a user's recent activity. Natural-language description of the desired output (e.g., `"A bulleted list of key findings"`). Guides the agent's response style. **Per-execution LLM provider override.** Use the provider's internal identifier (e.g. `openai`, `anthropic`, `bedrock`) from `GET /v1/misc/llm_providers`. Omit to use the agent's configured provider. **Per-execution model override.** Must be a valid model under the chosen provider (`GET /v1/misc/llm_providers/{provider_identifier}/models`). Examples: `claude-sonnet-4-6`, `gpt-5`, `gemini-2.0-flash`. Omit to use the agent's configured model. **Per-execution reasoning-effort override** for reasoning-capable models (e.g. GPT-5). One of `low`, `medium`, `high`, `xhigh`. Omit to use the agent's configured reasoning effort. ## Query Parameters Agent version to invoke. Defaults to the latest deployed version. Use `"draft"` to test undeployed changes. ## Response The response is the full task object. The key fields you'll use: Task/thread ID. Pass this back as `id` in your next request to continue the conversation. `completed`, `failed`, `error`, or `stopped` The agent's response. If `output_format` is `json`, this is a JSON string — parse it with `JSON.parse()` or `jq`. ISO 8601 timestamp when the task was created ISO 8601 timestamp when the task completed Effective LLM provider used for this execution. Reflects the per-execution override when supplied, otherwise the agent's configured provider. Effective model name used for this execution. Reflects the per-execution override when supplied, otherwise the agent's configured model. Effective reasoning effort used for this execution. One of `low`, `medium`, `high`, `xhigh`. Reflects the per-execution override when supplied, otherwise the agent's configured reasoning effort. ## Simplest Possible Invoke ```bash theme={"dark"} curl -X POST "https://api.xpander.ai/v1/agents//invoke" \ -H "Content-Type: application/json" \ -H "x-api-key: " \ -d '{"input": {"text": "What is xpander.ai?"}}' ``` Extract just the result: ```bash theme={"dark"} curl -s ... | jq -r '.result' ``` ## Multi-Turn Conversation Pass the `id` from the first response to continue the thread: ```bash theme={"dark"} # Turn 1 curl -s -X POST "https://api.xpander.ai/v1/agents//invoke" \ -H "Content-Type: application/json" \ -H "x-api-key: " \ -d '{"input": {"text": "Hi, my name is David and I work at xpander.ai"}}' # Response includes: "id": "6525177e-06a1-4063-82fe-37382d2302a5" # Turn 2 — pass the same id curl -s -X POST "https://api.xpander.ai/v1/agents//invoke" \ -H "Content-Type: application/json" \ -H "x-api-key: " \ -d '{ "input": {"text": "What is my name and where do I work?"}, "id": "6525177e-06a1-4063-82fe-37382d2302a5" }' # Agent responds: "Your name is David and you work at xpander.ai." ``` The agent remembers all previous messages in the thread. Always reuse the same `id` for follow-ups. ## With User Identity Pass the required user fields so the agent can personalize responses and use identity-aware tools: ```bash theme={"dark"} curl -s -X POST "https://api.xpander.ai/v1/agents//invoke" \ -H "Content-Type: application/json" \ -H "x-api-key: " \ -d '{ "input": { "text": "What is my user ID and email?", "user": { "id": "user-123", "email": "david@xpander.ai" } } }' ``` ```json theme={"dark"} { "status": "completed", "result": "Your user ID is user-123 and your email is david@xpander.ai." } ``` The `user` object is visible to the agent as context. Both `id` and `email` are required. ## With MCP OAuth Pass `user_oidc_token` when the agent uses MCP tools that require OAuth on behalf of the user: ```bash theme={"dark"} curl -s -X POST "https://api.xpander.ai/v1/agents//invoke" \ -H "Content-Type: application/json" \ -H "x-api-key: " \ -d '{ "input": { "text": "Create a calendar event for tomorrow at 10am", "user": { "id": "user-123", "email": "david@xpander.ai" } }, "user_oidc_token": "USER_OIDC_TOKEN" }' ``` ## Processing Files Files passed in `input.files` are downloaded and injected directly into the LLM context window by default. This works well for small-to-medium files: ```bash theme={"dark"} curl -s -X POST "https://api.xpander.ai/v1/agents//invoke" \ -H "Content-Type: application/json" \ -H "x-api-key: " \ -d '{ "input": { "text": "What is the abstract of this paper?", "files": ["https://assets.xpanderai.io/static/pdf/bitcoin.pdf"] } }' ``` ```json theme={"dark"} { "status": "completed", "result": "The abstract describes a peer-to-peer electronic cash system that enables direct online payments without financial institutions, solving the double-spending problem through a distributed network using proof-of-work and cryptographic signatures." } ``` The 9-page Bitcoin whitepaper (above) processes successfully — its content fits within the model's context window. ### Large Files Fail with Direct Injection Large files will exceed the model's context limit and return an error: ```bash theme={"dark"} # This 185-page PDF will fail — too large for the context window curl -s -X POST "https://api.xpander.ai/v1/agents//invoke" \ -H "Content-Type: application/json" \ -H "x-api-key: " \ -d '{ "input": { "text": "What year was the Apple Macintosh introduced?", "files": ["https://assets.xpanderai.io/static/pdf/Introducing_the_Apple_Macintosh_1984.pdf"] } }' ``` ```json theme={"dark"} { "status": "error", "result": "Error code: 413 - {'error': {'type': 'request_too_large', 'message': 'Request exceeds the maximum size'}}" } ``` Files are injected into the LLM context by default. Documents over \~100 pages will typically exceed the model's token limit. For large documents, use a [Knowledge Base](/api-reference/v1/knowledge/create-knowledge-base) instead — add the document to a KB, attach it to the agent, and the agent will search it automatically via RAG. ### Disable Context Injection Set `disable_attachment_injection: true` to pass the file URL to the agent's tools without injecting its content into the LLM prompt: ```bash theme={"dark"} curl -s -X POST "https://api.xpander.ai/v1/agents//invoke" \ -H "Content-Type: application/json" \ -H "x-api-key: " \ -d '{ "input": { "text": "Analyze this dataset", "files": ["https://example.com/data.csv"] }, "disable_attachment_injection": true }' ``` With this flag, the file URL is available to the agent's tools but the raw content is not prepended to the prompt. Use this when you want the agent's tools to process the file rather than the LLM reading it directly. For very large files (185+ pages), even `disable_attachment_injection: true` may not be enough — the file can exceed the HTTP request size limit before reaching the LLM. Use a [Knowledge Base](/api-reference/v1/knowledge/create-knowledge-base) for production workflows with large documents. ## Per-Request Instruction Override Append instructions for this specific invocation without changing the agent's configuration: ```bash theme={"dark"} curl -s -X POST "https://api.xpander.ai/v1/agents//invoke" \ -H "Content-Type: application/json" \ -H "x-api-key: " \ -d '{ "input": {"text": "Tell me about xpander pricing"}, "title": "Pricing Inquiry", "instructions_override": "Always respond in exactly 2 sentences. Never use emojis." }' ``` ```json theme={"dark"} { "status": "completed", "title": "Pricing Inquiry", "result": "xpander.ai offers two main pricing tiers: a Free plan with 2 serverless agents and 100 AI actions, and an In-House plan at $940/month for up to 10 agents and 200K actions. You can deploy on xpander's managed cloud or your own infrastructure." } ``` ## Per-Execution LLM Override Override the agent's configured provider, model, or reasoning effort for a single invocation without mutating the agent. Useful for A/B testing models, routing specific requests to a stronger or cheaper model, or dialing up reasoning effort on complex prompts: ```bash theme={"dark"} curl -s -X POST "https://api.xpander.ai/v1/agents//invoke" \ -H "Content-Type: application/json" \ -H "x-api-key: " \ -d '{ "input": {"text": "Summarize the attached research paper"}, "llm_model_provider": "openai", "llm_model_name": "gpt-5", "llm_reasoning_effort": "high" }' ``` All three fields are optional and independent — supply only the ones you want to override. Omitted fields fall back to the agent's configured values. The response object includes the **effective** `llm_model_provider`, `llm_model_name`, and `llm_reasoning_effort` that were actually used, so downstream metrics and dashboards correctly attribute the run. ## Structured JSON Output Request structured output with a JSON Schema: ```bash theme={"dark"} curl -s -X POST "https://api.xpander.ai/v1/agents//invoke" \ -H "Content-Type: application/json" \ -H "x-api-key: " \ -d '{"input": {"text": "Look up Stripe"}}' ``` To configure `output_format` and `output_schema` for structured output, use the [Update Agent](/api-reference/v1/agents/update-agent) endpoint or configure it in the dashboard under the Output tab. ## Example Response ```json theme={"dark"} { "id": "6525177e-06a1-4063-82fe-37382d2302a5", "agent_id": "", "organization_id": "", "status": "completed", "input": { "text": "What is xpander.ai in one sentence?", }, "result": "xpander.ai is a full-stack platform for building, deploying, and running autonomous AI agents in production.", "source": "api", "think_mode": "default", "disable_attachment_injection": false, "created_at": "2026-02-07T10:15:22.100233Z", "started_at": "2026-02-07T10:15:22.500000Z", "finished_at": "2026-02-07T10:15:28.997811Z", "execution_attempts": 1, "llm_model_provider": "anthropic", "llm_model_name": "claude-sonnet-4-6", "llm_reasoning_effort": "medium" } ``` ## See Also * [Invoke Agent (Async)](/api-reference/v1/agents/invoke-async) — returns immediately with a task ID for polling * [Invoke Agent (Stream)](/api-reference/v1/agents/invoke-stream) — real-time SSE stream of agent activity * [Get Thread](/api-reference/v1/tasks/get-thread) — retrieve the full conversation history * [Webhook documentation](/guides/deploy/webhooks) — trigger agents from external systems via the auto-generated `webhook_url` # List Agents Source: https://docs.xpander.ai/api-reference/v1/agents/list-agents GET /v1/agents Retrieve a paginated list of agents with core metadata. The response may include additional summary fields beyond ID, name, and status. Retrieve a paginated list of agents for browsing and selection. Although this is the lighter-weight listing endpoint, the payload typically includes core deployment and model metadata and may include additional summary fields such as instructions or compatibility flags. This endpoint returns standard agents. Workflows (agents of type `orchestration`) are listed separately by [List Workflows](/api-reference/v1/workflows/list-workflows), so the count here can be lower than the total number of agents in your organization. ## Query Parameters Page number (starting from 1) Items per page (maximum 50) ## Response Returns a paginated list of agent summaries. Treat unknown fields as forward-compatible metadata. Array of agent objects Unique identifier for the agent (UUID format) Display name of the agent Brief description of the agent's purpose Emoji icon representing the agent Current deployment status: ACTIVE, INACTIVE Organization UUID this agent belongs to Deployment method: serverless or null ISO timestamp of when the agent was created UUID of the user who created the agent Resolved creator details, one per agent item — no extra request needed. `null` when `created_by` is empty or the user cannot be resolved — null-check before reading sub-fields. User UUID Display name — first + last name. Falls back to email, then id, when the name is missing. Not guaranteed to be a real first/last name. User email High-level role, goal, and general instructions for the agent (nullable) LLM provider: openai, anthropic, etc. Specific model version (e.g., gpt-4o, gpt-4.1) Agent framework used (e.g., agno) Agent type: `manager`, `regular`, `a2a`, `curl`, or `orchestration` Custom LLM base URL when the agent uses a proxied or self-hosted model endpoint (nullable) Whether the agent has unpublished configuration changes Total number of agents across all pages Current page number Number of items per page Total number of pages available ## Example Request ```bash theme={"dark"} curl -X GET -H "x-api-key: " \ "https://api.xpander.ai/v1/agents?page=1&per_page=2" ``` ## Example Response ```json theme={"dark"} { "items": [ { "id": "", "name": "Product Specialist", "description": "Processes queries to provide comprehensive product information", "icon": "🚀", "status": "ACTIVE", "organization_id": "", "deployment_type": "serverless", "created_at": "2026-02-05T18:35:04.724091Z", "created_by": "", "created_by_details": { "id": "", "name": "Jane Doe", "email": "jane@acme.com" }, "instructions": { "role": [ "Answer product questions clearly and accurately" ], "goal": [ "Help users find the right product quickly" ], "general": "I am a product specialist focused on concise, accurate answers." }, "model_provider": "openai", "model_name": "gpt-5.2", "framework": "agno", "type": "manager", "llm_api_base": null, "has_pending_changes": false } ], "total": 12, "page": 1, "per_page": 20, "total_pages": 1 } ``` ## Notes * `/v1/agents` is the lighter-weight listing endpoint, but the response includes more than just `id`, `name`, and `status` * Additional fields may appear over time; client code should ignore unknown keys * The `items` array is sorted by creation date (newest first) * Use pagination to handle large result sets efficiently * Status values are: `ACTIVE` (deployed and ready), `INACTIVE` (not deployed) * See [List Agents (Full Details)](/api-reference/v1/agents/list-agents-full) for complete agent configuration # List Agents (Full Details) Source: https://docs.xpander.ai/api-reference/v1/agents/list-agents-full GET /v1/agents/full Retrieve a paginated list of AI agents in the simplified view (tools as one flat list, no low-level graph/oas). Retrieve a paginated list of AI agents. Each item is the **simplified agent view** — core configuration plus a flat `tools` array (see [Get Agent](/api-reference/v1/agents/get-agent) for the per-item field shape, including the `AgentTool` object). Low-level `graph`, `attached_tools`, and `oas` are not included; manage tools via the [Tools API](/api-reference/v1/tools/list-tools). ## Query Parameters Page number (starting from 1) Items per page (maximum 50) ## Response Returns a paginated list of agents with complete details: Array of complete agent objects Unique identifier for the agent (UUID format) URL-safe unique name for the agent Display name of the agent Detailed description of the agent's purpose and capabilities Emoji icon representing the agent Current deployment status: ACTIVE, INACTIVE Organization UUID this agent belongs to Deployment method: serverless or null Agent framework used (e.g., agno) Agent type: `manager`, `regular`, `a2a`, `curl`, or `orchestration` ISO timestamp of when the agent was created UUID of the user who created the agent Resolved creator details, one per agent item — no extra request needed. `null` when `created_by` is empty or the user cannot be resolved — null-check before reading sub-fields. User UUID Display name — first + last name. Falls back to email, then id, when the name is missing. Not guaranteed to be a real first/last name. User email Complete system instructions configuration with role, goal, and general fields LLM provider: openai, anthropic, etc. Specific model version (e.g., gpt-4o, gpt-4.1) Array of tool configurations attached to this agent Array of knowledge base IDs attached to this agent Visual graph representation of agent's tool and MCP connections Access control scope: organizational, team, or private Total number of agents across all pages Current page number Number of items per page Total number of pages available ## Example Request ```bash theme={"dark"} curl -X GET -H "x-api-key: " \ "https://api.xpander.ai/v1/agents/full?page=1&per_page=2" ``` ## Example Response ```json theme={"dark"} { "items": [ { "id": "", "unique_name": "product-specialist", "name": "Product Specialist", "description": "Processes queries to provide comprehensive product information", "icon": "🚀", "status": "ACTIVE", "organization_id": "", "deployment_type": "serverless", "framework": "agno", "type": "manager", "created_at": "2026-02-05T18:35:04.724091Z", "created_by": "", "created_by_details": { "id": "", "name": "Jane Doe", "email": "jane@acme.com" }, "model_provider": "openai", "model_name": "gpt-4.1", "instructions": { "role": [ "You are a product specialist assistant" ], "goal": [ "Provide accurate product information to customers" ], "general": "Be helpful and professional" }, "tools": [ { "id": "search-products", "name": "Search Products", "method": "get", "path": "/products/search" } ], "knowledge_bases": [], "graph": [], "access_scope": "organizational" } ], "total": 41, "page": 1, "per_page": 2, "total_pages": 21 } ``` ## Notes * This endpoint returns complete agent configurations, which may be slower than the minimal list endpoint * Use the minimal list endpoint (`GET /v1/agents`) if you only need basic agent information * The response is automatically filtered based on your API key's permissions * Large responses may take longer to retrieve due to nested configurations ## See Also * [List Agents (Minimal)](/api-reference/v1/agents/list-agents) - Lightweight endpoint for basic agent info * [Get Agent](/api-reference/v1/agents/get-agent) - Get complete details for a single agent # Create Scheduled Task Source: https://docs.xpander.ai/api-reference/v1/agents/scheduled-tasks/create-scheduled-task POST /v1/agents/{agent_id}/scheduled-tasks Create a recurring scheduled task (cron + prompt) for an agent. Create a recurring scheduled task. The change takes effect immediately — the agent runs the given prompt on every cron match. ## Request Body Cron expression (5-field crontab, UTC). Example: `0 9 * * *` runs daily at 09:00 UTC. Instruction the agent runs on each fire. Optional human-readable label for the task. Create the task active (default) or paused. ## Example Request ```bash theme={"dark"} curl -X POST -H "x-api-key: " -H "Content-Type: application/json" \ "https://api.xpander.ai/v1/agents//scheduled-tasks" \ -d '{ "cron": "0 9 * * *", "prompt": "Summarize yesterday'\''s support tickets and post to #ops.", "title": "Daily ticket digest" }' ``` ## Example Response ```json theme={"dark"} { "id": "", "title": "Daily ticket digest", "cron": "0 9 * * *", "prompt": "Summarize yesterday's support tickets and post to #ops.", "enabled": true } ``` # Delete Scheduled Task Source: https://docs.xpander.ai/api-reference/v1/agents/scheduled-tasks/delete-scheduled-task DELETE /v1/agents/{agent_id}/scheduled-tasks/{task_id} Delete a scheduled task by its id. Permanently remove a scheduled task. To stop a task temporarily without losing its config, use [Update Scheduled Task](/api-reference/v1/agents/scheduled-tasks/update-scheduled-task) with `enabled: false` instead. ## Example Request ```bash theme={"dark"} curl -X DELETE -H "x-api-key: " \ "https://api.xpander.ai/v1/agents//scheduled-tasks/" ``` ## Example Response ```json theme={"dark"} { "deleted": true } ``` # List Scheduled Tasks Source: https://docs.xpander.ai/api-reference/v1/agents/scheduled-tasks/list-scheduled-task GET /v1/agents/{agent_id}/scheduled-tasks List an agent's recurring scheduled tasks. Returns the recurring scheduled tasks configured on an agent. A scheduled task runs the agent on a cron schedule with a fixed prompt. ## Response Array of scheduled tasks. Task id — pass it to update, run, or delete the task. Human-readable label. Cron expression (5-field crontab, UTC), e.g. `0 9 * * *`. Instruction the agent runs on each fire. Whether the task is active. Disabled tasks keep their config but do not fire. ## Example Request ```bash theme={"dark"} curl -X GET -H "x-api-key: " \ "https://api.xpander.ai/v1/agents//scheduled-tasks" ``` ## Example Response ```json theme={"dark"} [ { "id": "", "title": "Daily ticket digest", "cron": "0 9 * * *", "prompt": "Summarize yesterday's support tickets and post to #ops.", "enabled": true } ] ``` # Run Scheduled Task Now Source: https://docs.xpander.ai/api-reference/v1/agents/scheduled-tasks/run-scheduled-task POST /v1/agents/{agent_id}/scheduled-tasks/{task_id}/run Fire a scheduled task immediately, regardless of its cron schedule. Trigger a scheduled task right away without waiting for its next cron match. Useful for testing a task or running it on demand. The run is executed asynchronously; inspect it via the agent's [tasks](/api-reference/v1/agents/get-agent-tasks). ## Example Request ```bash theme={"dark"} curl -X POST -H "x-api-key: " \ "https://api.xpander.ai/v1/agents//scheduled-tasks//run" ``` ## Example Response ```json theme={"dark"} { "id": "", "status": "running" } ``` # Update Scheduled Task Source: https://docs.xpander.ai/api-reference/v1/agents/scheduled-tasks/update-scheduled-task PATCH /v1/agents/{agent_id}/scheduled-tasks/{task_id} Update a scheduled task's cron, prompt, title, or enabled state. Update any subset of a scheduled task's fields. Set `enabled: false` to **pause** a task without losing its config; set `enabled: true` to resume. Changes take effect immediately. ## Request Body New cron expression (5-field crontab, UTC). New instruction. New label. Pause (`false`) or resume (`true`) without losing config. ## Example Request ```bash theme={"dark"} # Pause a task curl -X PATCH -H "x-api-key: " -H "Content-Type: application/json" \ "https://api.xpander.ai/v1/agents//scheduled-tasks/" \ -d '{ "enabled": false }' ``` ## Example Response ```json theme={"dark"} { "id": "", "title": "Daily ticket digest", "cron": "0 9 * * *", "prompt": "Summarize yesterday's support tickets and post to #ops.", "enabled": false } ``` # Cancel Self-Schedule Source: https://docs.xpander.ai/api-reference/v1/agents/self-schedules/cancel-self-schedule DELETE /v1/agents/{agent_id}/self-schedules/{schedule_id} Cancel a pending self-scheduled run by its id. Cancel a pending self-scheduled run before it fires. ## Example Request ```bash theme={"dark"} curl -X DELETE -H "x-api-key: " \ "https://api.xpander.ai/v1/agents//self-schedules/" ``` ## Example Response ```json theme={"dark"} { "status": true } ``` # Get Self-Schedule Settings Source: https://docs.xpander.ai/api-reference/v1/agents/self-schedules/get-self-schedule-settings GET /v1/agents/{agent_id}/self-schedules/settings Read whether the agent may schedule its own future runs, and its per-task cap. Returns the agent's self-scheduling capability. An agent can only book its own future runs when `can_self_schedule` is enabled. ## Response Whether the agent may schedule its own future runs. Per-task lifetime cap on chained self-schedules (1–1000). ## Example Request ```bash theme={"dark"} curl -X GET -H "x-api-key: " \ "https://api.xpander.ai/v1/agents//self-schedules/settings" ``` ## Example Response ```json theme={"dark"} { "can_self_schedule": true, "max_self_schedules": 5 } ``` # List Self-Schedules Source: https://docs.xpander.ai/api-reference/v1/agents/self-schedules/list-self-schedule GET /v1/agents/{agent_id}/self-schedules List an agent's self-scheduled future runs. Self-schedules are **one-shot future runs an agent books for itself at runtime** (when self-scheduling is enabled). This endpoint lists them — it does not create them. Optionally filter by status. ## Query Parameters Filter by status: `scheduled`, `completed`, or `failed`. ## Response Array of self-schedules. Self-schedule id — pass it to cancel the run. Owning agent id. Execution thread the run continues, if any. Instruction for the scheduled run. When the run fires (ISO-8601 UTC). `scheduled`, `completed`, or `failed`. Creation timestamp. Last update timestamp. ## Example Request ```bash theme={"dark"} curl -X GET -H "x-api-key: " \ "https://api.xpander.ai/v1/agents//self-schedules?status=scheduled" ``` ## Example Response ```json theme={"dark"} [ { "id": "", "agent_id": "", "task_id": "", "prompt": "Follow up on the open incident.", "run_at": "2026-07-01T09:00:00Z", "status": "scheduled", "created_at": "2026-06-30T09:00:00Z", "updated_at": "2026-06-30T09:00:00Z" } ] ``` # Set Self-Schedule Settings Source: https://docs.xpander.ai/api-reference/v1/agents/self-schedules/set-self-schedule-settings PUT /v1/agents/{agent_id}/self-schedules/settings Enable or disable the agent's self-scheduling capability and its per-task cap. Enable or disable whether the agent can schedule its own future runs, and optionally set the per-task cap on chained self-schedules. ## Request Body Whether the agent may schedule its own future runs. Per-task lifetime cap on chained self-schedules. Must be between 1 and 1000. ## Example Request ```bash theme={"dark"} curl -X PUT -H "x-api-key: " -H "Content-Type: application/json" \ "https://api.xpander.ai/v1/agents//self-schedules/settings" \ -d '{ "can_self_schedule": true, "max_self_schedules": 5 }' ``` ## Example Response ```json theme={"dark"} { "can_self_schedule": true, "max_self_schedules": 5 } ``` # Add Agent Tool Source: https://docs.xpander.ai/api-reference/v1/agents/tools/add-agent-tool POST /v1/agents/{agent_id}/tools Attach a tool to an agent (action, custom_function, mcp, agent, or workflow). The API handles catalog resolution and graph wiring. The request body is discriminated by `type`: * `action` — `{ "type": "action", "connection_id": "...", "operation_ids": [""] }` * `custom_function` — `{ "type": "custom_function", "custom_function_id": "..." }` * `mcp` (registry) — `{ "type": "mcp", "mcp_id": "" }` * `mcp` (inline) — `{ "type": "mcp", "url": "https://...", "name": "...", "transport": "streamable-http" }` * `agent` (sub-agent) — `{ "type": "agent", "agent_id": "..." }` * `workflow` — `{ "type": "workflow", "workflow_id": "..." }` # List Agent Tools Source: https://docs.xpander.ai/api-reference/v1/agents/tools/list-agent-tools GET /v1/agents/{agent_id}/tools List the tools attached to an agent in a simple, unified shape. # Remove Agent Tool Source: https://docs.xpander.ai/api-reference/v1/agents/tools/remove-agent-tool DELETE /v1/agents/{agent_id}/tools/{tool_id} Remove a tool from an agent by its tool id (the id returned by List Agent Tools). # Update Agent Source: https://docs.xpander.ai/api-reference/v1/agents/update-agent PATCH /v1/agents/{agent_id} Update an existing AI agent's configuration, tools, or knowledge bases Modify an agent's configuration. Only provided fields will be updated. At least one field must be provided. To add or remove **tools** (connector actions, custom functions, MCP servers, sub-agents, workflows), prefer the dedicated agent tools endpoints — [List](/api-reference/v1/agents/tools/list-agent-tools) / [Add](/api-reference/v1/agents/tools/add-agent-tool) / [Remove](/api-reference/v1/agents/tools/remove-agent-tool). They handle catalog resolution and graph wiring for you, instead of hand-editing low-level `graph`/`attached_tools`. ## Path Parameters Unique identifier of the agent to update (UUID format) ## Query Parameters Automatically deploy the agent after updating to apply changes immediately. Without this, changes are staged but not active until a separate PUT deploy call. ## Request Body Display name for the agent Description of the agent's purpose and capabilities System instructions configuration Array of role descriptions Array of goal descriptions General instructions text Emoji icon representing the agent AI model provider (e.g., `openai`) Specific model version (e.g., `gpt-4o`, `gpt-4.1`) Agent status (enum: `ACTIVE`, `INACTIVE`) Custom API base URL for LLM provider (for AI Gateway configurations) Custom HTTP headers to include in LLM requests for gateway integration Reasoning effort level for the LLM (e.g., `low`, `medium`, `high`) Output format: `text` or `json` JSON schema for structured output when `output_format` is `json` Natural-language description of the desired output Target environment ID Access control scope: `personal` or `organizational` Agent type: `manager`, `regular`, `a2a`, `curl` Array of connector tool attachments with connection IDs and selected operation IDs Agent workflow graph configuration defining tool execution order Array of knowledge base IDs to attach to the agent Advanced agent settings including memory, session storage, tool limits, and safety features Task-level strategies for retry, stop conditions, and iteration Notification configuration (Slack, email, webhook) for agent events Deep planning configuration for complex multi-step tasks Voice ID for text-to-speech output Source node configurations (e.g., Slack, web UI triggers) Whether the agent requires human approval for tool calls ## Response Returns the updated `AIAgent` object with all current configuration. ## Example Request ```bash theme={"dark"} curl -X PATCH -H "x-api-key: " \ -H "Content-Type: application/json" \ -d '{ "name": "Customer Support Agent", "model_provider": "anthropic", "model_name": "claude-sonnet-4-5-20250929", "instructions": { "role": [ "Always greet the customer warmly", "Search the knowledge base before answering", "Escalate billing issues" ], "goal": [ "Resolve customer inquiries on first contact", "Maintain a friendly tone" ], "general": "You are a customer support agent..." }, "access_scope": "personal" }' \ https://api.xpander.ai/v1/agents/ ``` ## Example Response ```json theme={"dark"} { "id": "", "unique_name": "customer-support-agent", "name": "Customer Support Agent", "status": "ACTIVE", "organization_id": "", "deployment_type": "serverless", "framework": "agno", "type": "manager", "version": 2, "has_pending_changes": false, "is_latest": false, "instructions": { "role": [ "Always greet the customer warmly", "Search the knowledge base before answering", "Escalate billing issues" ], "goal": [ "Resolve customer inquiries on first contact", "Maintain a friendly tone" ], "general": "You are a customer support agent..." }, "access_scope": "personal", "model_provider": "anthropic", "model_name": "claude-sonnet-4-5-20250929", "tools": [], "knowledge_bases": [] } ``` ## Info The PATCH endpoint updates agent configuration fields such as `name`, `instructions`, `model_provider`, `model_name`, `output_format`, `expected_output`, and `access_scope`. To attach tools or knowledge bases, use the [xpander.ai platform](https://chat.xpander.ai) or the [Python SDK](/api-reference/sdk). ## Notes * At least one field must be provided in the request body * Only the specified fields will be updated; other fields remain unchanged * Use `deploy=true` query parameter to automatically deploy after updating * Without `deploy=true`, changes are staged and require a separate [Deploy Agent](/api-reference/v1/agents/deploy-agent) call * `attached_tools`, `knowledge_bases`, and `graph` can now be updated via PATCH # Bash Source: https://docs.xpander.ai/api-reference/v1/agents/workspace/bash POST /v1/agents/{agent_id}/workspace/bash Execute a shell command inside the agent's workspace Run a shell command inside the per-agent workspace. ## Path Parameters Agent ID (UUID) ## Request Body Shell command to execute inside the workspace. Maximum execution time in seconds before the command is terminated. Optional working directory for the command. Defaults to the workspace root when empty. ## Response Result status of the operation (e.g., `ok`). Standard output captured from the command. Standard error captured from the command. Process exit code. ## Example Request ```bash theme={"dark"} curl -X POST "https://api.xpander.ai/v1/agents//workspace/bash" \ -H "Content-Type: application/json" \ -H "x-api-key: " \ -d '{ "command": "ls -la", "timeout": 300, "working_dir": "" }' ``` ## Notes * The workspace is per-agent and persists between calls, so files created here remain available to subsequent workspace operations for the same agent. * Commands are run as an unprivileged user. Avoid commands that require elevated permissions. ## See Also * [File Write](/api-reference/v1/agents/workspace/file-write) * [File Read](/api-reference/v1/agents/workspace/file-read) * [Grep](/api-reference/v1/agents/workspace/grep) # File Edit Source: https://docs.xpander.ai/api-reference/v1/agents/workspace/file-edit POST /v1/agents/{agent_id}/workspace/file_edit Edit a file in the agent's workspace by replacing an exact text occurrence Edit a file in the per-agent workspace by replacing an exact text occurrence. `old_text` must match the existing file content exactly, including whitespace and indentation. ## Path Parameters Agent ID (UUID) ## Request Body Path to the file to edit, relative to the workspace root. Exact text to find and replace. Must match existing file content, including whitespace. Replacement text. Use an empty string to delete the matched content. ## Response Result status (e.g., `ok`). Path of the file that was edited. ## Example Request ```bash theme={"dark"} curl -X POST "https://api.xpander.ai/v1/agents//workspace/file_edit" \ -H "Content-Type: application/json" \ -H "x-api-key: " \ -d '{ "path": "app.py", "old_text": "DEBUG = True", "new_text": "DEBUG = False" }' ``` ## Notes * The match is exact and case-sensitive. If `old_text` appears more than once in the file, the request fails — include additional surrounding context in `old_text` to make the match unique. * To apply several edits atomically, use [Multi Edit](/api-reference/v1/agents/workspace/multi-edit) instead. ## See Also * [Multi Edit](/api-reference/v1/agents/workspace/multi-edit) * [File Write](/api-reference/v1/agents/workspace/file-write) * [File Read](/api-reference/v1/agents/workspace/file-read) # File Read Source: https://docs.xpander.ai/api-reference/v1/agents/workspace/file-read POST /v1/agents/{agent_id}/workspace/file_read Read a file from the agent's workspace filesystem Read a file from the per-agent workspace filesystem. Optional line ranges let you page through large files without loading them entirely. ## Path Parameters Agent ID (UUID) ## Request Body Path to the file relative to the workspace root. 1-based line number to start reading from. Optional; reads from the beginning when omitted. 1-based line number to stop reading at (inclusive). Optional; reads to the end when omitted. Text encoding used to decode the file contents. ## Response Result status (e.g., `ok`). File contents within the requested range. The file path that was read. ## Example Request ```bash theme={"dark"} curl -X POST "https://api.xpander.ai/v1/agents//workspace/file_read" \ -H "Content-Type: application/json" \ -H "x-api-key: " \ -d '{ "path": "config.yaml", "start_line": 1, "end_line": 50, "encoding": "utf-8" }' ``` ## Notes * Paths must be relative to the workspace root. Absolute paths are rejected. * For binary files, set `encoding` appropriately or use [File Share](/api-reference/v1/agents/workspace/file-share) to retrieve the file via a public URL. ## See Also * [File Write](/api-reference/v1/agents/workspace/file-write) * [File Edit](/api-reference/v1/agents/workspace/file-edit) * [Grep](/api-reference/v1/agents/workspace/grep) # File Share Source: https://docs.xpander.ai/api-reference/v1/agents/workspace/file-share POST /v1/agents/{agent_id}/workspace/file_share Publish a file from the agent's workspace to a public CDN URL Publish a file from the per-agent workspace to a public CDN URL that can be shared externally (for example, to return a download link from an agent response). ## Path Parameters Agent ID (UUID) ## Request Body Path to the file in the workspace to publish. ## Response Result status (e.g., `ok`). Public CDN URL for the shared file. Original workspace file path. ## Example Request ```bash theme={"dark"} curl -X POST "https://api.xpander.ai/v1/agents//workspace/file_share" \ -H "Content-Type: application/json" \ -H "x-api-key: " \ -d '{ "path": "output/report.csv" }' ``` ## Notes * Shared URLs are unauthenticated — treat them as public links. Do not share files containing secrets. * The returned URL is served from the xpander CDN and is safe to include in agent responses or webhooks. ## See Also * [File Write](/api-reference/v1/agents/workspace/file-write) * [File Read](/api-reference/v1/agents/workspace/file-read) # File Write Source: https://docs.xpander.ai/api-reference/v1/agents/workspace/file-write POST /v1/agents/{agent_id}/workspace/file_write Create or overwrite a file in the agent's workspace filesystem Create or overwrite a file in the per-agent workspace filesystem. When `create_dirs` is `true`, any missing parent directories are created automatically. ## Path Parameters Agent ID (UUID) ## Request Body Destination file path relative to the workspace root. Full file content. Existing files are overwritten. When `true`, missing parent directories are created automatically. ## Response Result status (e.g., `ok`). Path of the file that was written. ## Example Request ```bash theme={"dark"} curl -X POST "https://api.xpander.ai/v1/agents//workspace/file_write" \ -H "Content-Type: application/json" \ -H "x-api-key: " \ -d '{ "path": "output/report.txt", "content": "Hello World\n", "create_dirs": true }' ``` ## Notes * `file_write` overwrites existing files. To modify an existing file in place, prefer [File Edit](/api-reference/v1/agents/workspace/file-edit) or [Multi Edit](/api-reference/v1/agents/workspace/multi-edit). * Paths must be relative to the workspace root. ## See Also * [File Read](/api-reference/v1/agents/workspace/file-read) * [File Edit](/api-reference/v1/agents/workspace/file-edit) * [File Share](/api-reference/v1/agents/workspace/file-share) # Glob Source: https://docs.xpander.ai/api-reference/v1/agents/workspace/glob POST /v1/agents/{agent_id}/workspace/glob Find files in the agent's workspace matching a glob pattern Find files in the per-agent workspace matching a glob pattern (e.g. `**/*.py`). Useful for discovering files before reading or editing them. ## Path Parameters Agent ID (UUID) ## Request Body Glob pattern to match (e.g. `**/*.py`). Directory to search from, relative to the workspace root. Defaults to the workspace root when omitted. Maximum number of matches to return. ## Response Result status (e.g., `ok`). Array of matching file paths. ## Example Request ```bash theme={"dark"} curl -X POST "https://api.xpander.ai/v1/agents//workspace/glob" \ -H "Content-Type: application/json" \ -H "x-api-key: " \ -d '{ "pattern": "**/*.py", "root_dir": "src", "max_results": 1000 }' ``` ## Notes * Use `**` to match across directory boundaries and `*` to match anything within a single path segment. * Combine with [Grep](/api-reference/v1/agents/workspace/grep) to search the contents of the matched files. ## See Also * [Grep](/api-reference/v1/agents/workspace/grep) * [File Read](/api-reference/v1/agents/workspace/file-read) # Grep Source: https://docs.xpander.ai/api-reference/v1/agents/workspace/grep POST /v1/agents/{agent_id}/workspace/grep Search for a regex pattern across files in the agent's workspace Search for a regex pattern across files in the per-agent workspace, with optional file-type filtering and surrounding context lines. ## Path Parameters Agent ID (UUID) ## Request Body Regular expression to search for. Directory or file path to search, relative to the workspace root. Optional filename glob to include (e.g. `*.py`). Number of context lines to include before and after each match. ## Response Result status (e.g., `ok`). Array of match objects, each including the file path, matching line, and surrounding context. ## Example Request ```bash theme={"dark"} curl -X POST "https://api.xpander.ai/v1/agents//workspace/grep" \ -H "Content-Type: application/json" \ -H "x-api-key: " \ -d '{ "pattern": "def main", "path": "src", "include": "*.py", "context_lines": 2 }' ``` ## Notes * `pattern` is a regex. Escape regex metacharacters if you want to match them literally. * Narrow the search with `path` and `include` for faster results on large workspaces. ## See Also * [Glob](/api-reference/v1/agents/workspace/glob) * [File Read](/api-reference/v1/agents/workspace/file-read) # Multi Edit Source: https://docs.xpander.ai/api-reference/v1/agents/workspace/multi-edit POST /v1/agents/{agent_id}/workspace/multi_edit Apply multiple file edits atomically in the agent's workspace Apply multiple file edits atomically. Each edit uses the same exact-match semantics as [File Edit](/api-reference/v1/agents/workspace/file-edit). If any edit fails, all changes are rolled back. ## Path Parameters Agent ID (UUID) ## Request Body Ordered list of edits to apply. Each item has: Path to the file to edit, relative to the workspace root. Exact text to replace. Must match existing file content. Replacement text. ## Response Result status (e.g., `ok`). ## Example Request ```bash theme={"dark"} curl -X POST "https://api.xpander.ai/v1/agents//workspace/multi_edit" \ -H "Content-Type: application/json" \ -H "x-api-key: " \ -d '{ "edits": [ { "path": "app.py", "old_text": "DEBUG = True", "new_text": "DEBUG = False" } ] }' ``` ## Notes * Edits are applied in the order provided. Later edits can operate on content produced by earlier edits in the same request. * If any single edit fails (e.g., `old_text` not found), the entire batch is rolled back so the workspace is not left in a half-applied state. ## See Also * [File Edit](/api-reference/v1/agents/workspace/file-edit) * [File Write](/api-reference/v1/agents/workspace/file-write) # Create Custom Function Source: https://docs.xpander.ai/api-reference/v1/custom_functions/create-custom-function POST /v1/custom_functions Create a new custom function with Python source code Create a new custom function. The code must define a function called `xpander_run_action(...)` that will be executed when the function is invoked. After creation, the function is automatically analyzed for safety and input schema extraction. ## Request Body Display name for the custom function Python source code. Must contain a `xpander_run_action(...)` function definition. Internal function name (defaults to sanitized version of `name`) Human-readable description of what the function does Execution limits Maximum execution time in seconds Maximum memory in MB ## Response Returns the created `CustomFunctionItem` with status `analysing`. The function transitions to `ready` once analysis completes. ## Example Request ```bash theme={"dark"} curl -X POST "https://api.xpander.ai/v1/custom_functions" \ -H "Content-Type: application/json" \ -H "x-api-key: " \ -d '{ "name": "Weather Lookup", "description": "Fetches current weather for a given city", "source_code": "import requests\n\ndef xpander_run_action(city: str) -> str:\n \"\"\"Get current weather for a city.\"\"\"\n resp = requests.get(f\"https://wttr.in/{city}?format=3\")\n return resp.text" }' ``` ## Notes * The `xpander_run_action` function is the entry point — it must be defined in the source code * After creation, the function is automatically analyzed for safety and input schema extraction * Status transitions: `analysing` → `ready` (success) or `analysing` → `error` (analysis failed) * Check `analysis_error_details` if the function moves to `error` status # Delete Custom Function Source: https://docs.xpander.ai/api-reference/v1/custom_functions/delete-custom-function DELETE /v1/custom_functions/{function_id} Permanently delete a custom function Permanently delete a custom function. Make sure to remove it from any agents' `attached_tools` and `graph` before deleting. ## Path Parameters Unique identifier of the custom function to delete ## Response Returns HTTP `202 Accepted` on successful deletion. ## Example Request ```bash theme={"dark"} curl -X DELETE -H "x-api-key: " \ "https://api.xpander.ai/v1/custom_functions/" ``` ## Notes * Remove the function from any agents' `attached_tools` and `graph` before deleting * This operation is permanent and cannot be undone # Execute Custom Function Source: https://docs.xpander.ai/api-reference/v1/custom_functions/execute-custom-function POST /v1/custom_functions/{function_id}/execute Execute a custom function with the provided parameters Execute a custom function directly with the provided parameters. The function must be in `ready` status. Parameters are passed as key-value pairs matching the function's `input_schema`. ## Path Parameters Unique identifier of the custom function to execute ## Request Body Pass parameters as key-value pairs matching the function's `input_schema`. The exact fields depend on the function definition. ## Response Returns the function execution result. ## Example Request ```bash theme={"dark"} curl -X POST "https://api.xpander.ai/v1/custom_functions//execute" \ -H "Content-Type: application/json" \ -H "x-api-key: " \ -d '{"city": "San Francisco"}' ``` ## Notes * The function must be in `ready` status — functions in `analysing` or `error` status cannot be executed * Parameters must match the function's `input_schema` (see [Get Custom Function](/api-reference/v1/custom_functions/get-custom-function)) * Useful for testing functions before attaching them to agents # Generate Custom Function Source: https://docs.xpander.ai/api-reference/v1/custom_functions/generate-custom-function POST /v1/custom_functions/generate AI-generate a custom function from a natural language description AI-generate a custom function from a natural language description. Provide a description of what the function should do, and optionally provide existing code to improve or a cURL command to convert into a function. ## Request Body Natural language description of what the function should do (e.g., "fetch stock prices from Yahoo Finance") Existing Python code to improve or refactor A cURL command to convert into a custom function ## Response The generated Python source code ready to use with [Create Custom Function](/api-reference/v1/custom_functions/create-custom-function) ## Example Request ```bash theme={"dark"} curl -X POST "https://api.xpander.ai/v1/custom_functions/generate" \ -H "Content-Type: application/json" \ -H "x-api-key: " \ -d '{"query": "Create a function that fetches the current Bitcoin price from CoinGecko API"}' ``` ## Notes * The generated code includes a `xpander_run_action(...)` entry point * Review the generated code before creating the function * You can provide `user_function` to improve existing code, or `import_curl` to convert a cURL command # Get Custom Function Source: https://docs.xpander.ai/api-reference/v1/custom_functions/get-custom-function GET /v1/custom_functions/{function_id} Get a custom function by ID, including its source code, input schema, and status Retrieve a custom function by its ID, including the full source code, auto-extracted input schema, and current status. ## Path Parameters Unique identifier of the custom function ## Response Returns the full `CustomFunctionItem` object. ## Example Request ```bash theme={"dark"} curl -X GET -H "x-api-key: " \ "https://api.xpander.ai/v1/custom_functions/" ``` # List Custom Functions Source: https://docs.xpander.ai/api-reference/v1/custom_functions/list-custom-functions GET /v1/custom_functions List all custom functions in the organization List all custom functions in your organization. Custom functions are user-defined Python functions that can be attached to agents as tools. ## Query Parameters Page number (starting from 1) Items per page (maximum 50) ## Response Array of custom function objects Unique identifier for the custom function Display name of the function Human-readable description Auto-generated technical description from code analysis Function status: `analysing`, `ready`, `error` Auto-extracted JSON schema for function parameters Python source code of the function Execution limits (timeout, memory, etc.) Organization UUID ISO timestamp of creation Total number of custom functions Current page number Items per page Total pages available ## Example Request ```bash theme={"dark"} curl -X GET -H "x-api-key: " \ "https://api.xpander.ai/v1/custom_functions?page=1&per_page=10" ``` ## Notes * Custom functions are attached to agents using `attached_tools` with `id='xpander-custom-functions'` * Functions in `analysing` status are being processed and not yet available for use # Update Custom Function Source: https://docs.xpander.ai/api-reference/v1/custom_functions/update-custom-function PATCH /v1/custom_functions/{function_id} Update an existing custom function Update an existing custom function. You can update the name, description, source code, and limits. If source code changes, the function is re-analyzed automatically. ## Path Parameters Unique identifier of the custom function ## Request Body All fields are optional. Only provided fields will be updated. Updated display name Updated description Updated Python source code (triggers re-analysis) Updated execution limits ## Response Returns the updated `CustomFunctionItem`. ## Example Request ```bash theme={"dark"} curl -X PATCH -H "x-api-key: " \ -H "Content-Type: application/json" \ -d '{"description": "Updated description", "source_code": "def xpander_run_action(city: str) -> str:\n return f\"Weather in {city}: Sunny\""}' \ "https://api.xpander.ai/v1/custom_functions/" ``` ## Notes * Changing `source_code` triggers automatic re-analysis — status resets to `analysing` * Non-code fields (name, description, limits) can be updated without triggering re-analysis # Add Documents to Knowledge Base Source: https://docs.xpander.ai/api-reference/v1/knowledge/add-documents POST /v1/knowledge/{kb_id}/documents Add one or more documents to a knowledge base Upload documents to a knowledge base by providing URLs. The documents will be downloaded, processed, and indexed for semantic search. ## Path Parameters Unique identifier of the knowledge base (UUID format) ## Request Body Array of document URLs to add to the knowledge base **Supported formats:** * PDF documents * Microsoft Word (.docx, .doc) * Text files (.txt, .md) * Web pages (HTML) * CSV and Excel files * Presentations (PPTX, PPT) * JSON and YAML files ## Response Returns an array of created document objects: Knowledge base ID Unique identifier for the document (UUID) - initially null, assigned after processing completes Document name (initially null) URL of the document ## Example Request ```bash theme={"dark"} curl -X POST -H "x-api-key: " \ -H "Content-Type: application/json" \ -d '{ "document_urls": [ "https://example.com/product-guide.pdf", "https://example.com/faq-page" ] }' \ https://api.xpander.ai/v1/knowledge//documents ``` ## Example Response ```json theme={"dark"} [ { "kb_id": "", "id": null, "name": null, "document_url": "https://example.com/product-guide.pdf" }, { "kb_id": "", "id": null, "name": null, "document_url": "https://example.com/faq-page" } ] ``` ## Processing Flow 1. **Upload** - Documents are queued for processing 2. **Download** - System downloads documents from provided URLs 3. **Extract** - Text content is extracted from documents 4. **Chunk** - Content is split into searchable chunks 5. **Embed** - Chunks are converted to vector embeddings 6. **Index** - Embeddings are stored in the vector database Processing typically takes 10-60 seconds per document depending on size. ## Supported File Types * **Documents:** PDF, DOCX, DOC, TXT, MD, RTF * **Spreadsheets:** CSV, XLSX, XLS * **Presentations:** PPTX, PPT * **Web:** HTML, XML * **Code:** JSON, YAML, various programming languages ## Notes * Documents must be publicly accessible via HTTP/HTTPS * Maximum file size: 50MB per document * The `id` field is `null` initially until the document is processed and indexed * The document ID is assigned after processing/indexing completes * Use [List Documents](/api-reference/v1/knowledge/list-documents) to check processing progress * Duplicate URLs will create separate document entries # Create Knowledge Base Source: https://docs.xpander.ai/api-reference/v1/knowledge/create-knowledge-base POST /v1/knowledge Creates a new knowledge base Create a new knowledge base in your organization to store and manage documents. ## Request Body Display name for the knowledge base Optional description of the knowledge base purpose ## Response Unique identifier for the knowledge base (UUID) Display name of the knowledge base Description of the knowledge base (nullable) Knowledge base type: `managed` UUID of the organization that owns this knowledge base Associated agent ID (nullable) Number of documents in the knowledge base (initially 0) ## Example Request ```bash theme={"dark"} curl -X POST -H "x-api-key: " \ -H "Content-Type: application/json" \ -d '{ "name": "Technical Documentation", "description": "Internal technical guides and API documentation" }' \ https://api.xpander.ai/v1/knowledge ``` ## Example Response ```json theme={"dark"} { "id": "", "name": "Product Catalog", "description": "Product information and specifications for customer support", "type": "managed", "organization_id": "", "agent_id": null, "total_documents": 0 } ``` ## Notes * New knowledge bases start with zero documents * Use the returned `id` to add documents via the [Add Documents](/api-reference/v1/knowledge/add-documents) endpoint # Delete Knowledge Base Document Source: https://docs.xpander.ai/api-reference/v1/knowledge/delete-document DELETE /v1/knowledge/{kb_id}/documents/{document_id} Delete a specific document from a knowledge base Permanently remove a document from a knowledge base. This deletes the document file, all extracted chunks, and vector embeddings. ## Path Parameters Unique identifier of the knowledge base (UUID format) Unique identifier of the document to delete (UUID format) ## Response Returns `202 Accepted` on successful deletion. ## Example Request ```bash theme={"dark"} curl -X DELETE -H "x-api-key: " \ https://api.xpander.ai/v1/knowledge//documents/ ``` ## Example Response ``` HTTP/1.1 202 Accepted Content-Type: application/json null ``` ## Notes * This action cannot be undone * All vector embeddings for this document will be removed from search * Agents using this knowledge base will no longer have access to this document's content * The document file itself is permanently deleted from storage * Returns 404 if the document or knowledge base is not found # Delete Knowledge Base Source: https://docs.xpander.ai/api-reference/v1/knowledge/delete-knowledge-base DELETE /v1/knowledge/{kb_id} Deletes knowledge base by ID Permanently delete a knowledge base and all its documents. This action cannot be undone. ## Path Parameters Unique identifier of the knowledge base to delete (UUID format) ## Response Returns `202 Accepted` on successful deletion. ## Example Request ```bash theme={"dark"} curl -X DELETE -H "x-api-key: " \ https://api.xpander.ai/v1/knowledge/ ``` ## Example Response ``` HTTP/1.1 202 Accepted Content-Type: application/json null ``` ## Notes * All documents in the knowledge base will be permanently removed * All vector embeddings will be deleted from the search index * Agents using this knowledge base will lose access to it * This action cannot be undone * Returns 404 if the knowledge base is not found # Get Knowledge Base Document Source: https://docs.xpander.ai/api-reference/v1/knowledge/get-document GET /v1/knowledge/{kb_id}/documents/{document_id} Get detailed information about a specific document in a knowledge base Retrieve complete details about a specific document including metadata, processing status, and content information. ## Path Parameters Unique identifier of the knowledge base (UUID format) Unique identifier of the document (UUID format) ## Response Knowledge base ID this document belongs to Unique identifier for the document (UUID) URL of the document UUID of the organization that owns this document Document name (typically the document URL) The extracted text content of the document ## Example Request ```bash theme={"dark"} curl -X GET -H "x-api-key: " \ "https://api.xpander.ai/v1/knowledge//documents/" ``` ## Example Response ```json theme={"dark"} { "kb_id": "", "id": "", "document_url": "https://example.com/product-guide.pdf", "organization_id": "", "name": "https://example.com/product-guide.pdf", "raw_data": "The extracted text content of the document..." } ``` ## Notes * The `raw_data` field contains the extracted text content of the document * Returns 404 if the document or knowledge base is not found # Get Knowledge Base Source: https://docs.xpander.ai/api-reference/v1/knowledge/get-knowledge-base GET /v1/knowledge/{kb_id} Get knowledge base details by ID Retrieve detailed information about a specific knowledge base including its configuration, document count, and metadata. ## Path Parameters Unique identifier of the knowledge base (UUID format) ## Response Unique identifier for the knowledge base (UUID) Display name of the knowledge base Optional description of the knowledge base purpose (can be null) Knowledge base type: `managed` UUID of the organization that owns this knowledge base UUID of the agent this knowledge base is attached to (can be null) Total number of documents in the knowledge base ## Example Request ```bash theme={"dark"} curl -X GET -H "x-api-key: " \ https://api.xpander.ai/v1/knowledge/ ``` ## Example Response ```json theme={"dark"} { "id": "73dc30ca-bdbf-42f7-a39f-93aff4f8522e", "name": "Product Catalog", "description": "Complete product information and specifications", "type": "managed", "organization_id": "", "agent_id": null, "total_documents": 12 } ``` ## Notes * Returns 404 if the knowledge base is not found or doesn't belong to your organization * Use this endpoint to verify knowledge base existence before adding documents # List Knowledge Base Documents Source: https://docs.xpander.ai/api-reference/v1/knowledge/list-documents GET /v1/knowledge/{kb_id}/documents Get paginated list of documents in a knowledge base Retrieve all documents stored in a specific knowledge base with pagination support. This endpoint returns document metadata including IDs and URLs. ## Path Parameters Unique identifier of the knowledge base (UUID format) ## Query Parameters Page number (starting from 1) Items per page (maximum 50) ## Response Array of document objects Knowledge base ID this document belongs to Unique identifier for the document (UUID) Document name (nullable) URL to access the document file Total number of documents in the knowledge base Current page number Number of items per page Total number of pages available ## Example Request ```bash theme={"dark"} curl -X GET -H "x-api-key: " \ "https://api.xpander.ai/v1/knowledge//documents?page=1&per_page=10" ``` ## Example Response ```json theme={"dark"} { "items": [ { "kb_id": "", "id": "", "name": "https://docs.example.com/quickstart", "document_url": "https://docs.example.com/quickstart" } ], "total": 1, "page": 1, "per_page": 10, "total_pages": 1 } ``` ## Notes * Documents are returned in the order they were added to the knowledge base * The `document_url` field contains the full URL to access the document file * Use this endpoint to audit what documents are in a knowledge base * Combine with [Get Document](/api-reference/v1/knowledge/get-document) to retrieve full document details # List Knowledge Bases Source: https://docs.xpander.ai/api-reference/v1/knowledge/list-knowledge-bases GET /v1/knowledge Returns a paginated list of knowledge bases Retrieve all knowledge bases in your organization with document counts and metadata. ## Query Parameters Page number (starting from 1) Items per page (maximum 50) ## Response Array of knowledge base objects Unique identifier for the knowledge base (UUID format) Display name of the knowledge base Description of the knowledge base content (nullable) Knowledge base type: `managed` Organization UUID this knowledge base belongs to Associated agent ID (nullable) Number of documents in this knowledge base Total number of knowledge bases Current page number Number of items per page Total number of pages available ## Example Request ```bash theme={"dark"} curl -X GET -H "x-api-key: " \ "https://api.xpander.ai/v1/knowledge?page=1&per_page=2" ``` ## Example Response ```json theme={"dark"} { "items": [ { "id": "73dc30ca-bdbf-42f7-a39f-93aff4f8522e", "name": "Product Catalog", "description": "Complete product information and specifications", "type": "managed", "organization_id": "", "agent_id": null, "total_documents": 12 }, { "id": "e21563bd-7c02-4f8f-9520-8c854f5c2ee6", "name": "Company Policies", "description": "Internal policies and procedures documentation", "type": "managed", "organization_id": "", "agent_id": null, "total_documents": 8 } ], "total": 5, "page": 1, "per_page": 2, "total_pages": 3 } ``` ## Notes * Knowledge bases are automatically filtered by your organization * `total_documents` reflects the number of documents currently indexed * Use pagination to retrieve large lists of knowledge bases # Search Knowledge Base Source: https://docs.xpander.ai/api-reference/v1/knowledge/search-knowledge-base GET /v1/knowledge/{kb_id}/search Search in knowledge base using vector search Perform semantic search across documents in a knowledge base using vector similarity. Returns the most relevant document chunks based on your query. ## Path Parameters Unique identifier of the knowledge base to search (UUID format) ## Query Parameters The search query text to find relevant documents Number of results to return (default: 5, maximum: 50) ## Response Returns a flat array of search results, each containing: The extracted text content from the matching document Relevance score (float, higher indicates better match) ## Example Request ```bash theme={"dark"} curl --request GET \ --url 'https://api.xpander.ai/v1/knowledge//search?search_query=pricing+plans&top_k=5' \ --header 'x-api-key: ' ``` ## Example Response ```json theme={"dark"} [ { "content": "The extracted text content from the matching document...", "score": 81.41 } ] ``` ## Notes * Search only returns results from documents with `status: "completed"` * Pending or failed documents are excluded from search results * Empty results indicate no matching content in the knowledge base * Returns 404 if the knowledge base is not found # Update Knowledge Base Source: https://docs.xpander.ai/api-reference/v1/knowledge/update-knowledge-base PATCH /v1/knowledge/{kb_id} Updates a knowledge base Modify a knowledge base's configuration. Only provided fields will be updated. ## Path Parameters Unique identifier of the knowledge base to update (UUID format) ## Request Body Display name for the knowledge base Optional description of the knowledge base purpose UUID of the agent to attach this knowledge base to ## Response Returns the updated knowledge base object with the structure matching [Get Knowledge Base](/api-reference/v1/knowledge/get-knowledge-base). ## Example Request ```bash theme={"dark"} curl -X PATCH -H "x-api-key: " \ -H "Content-Type: application/json" \ -d '{ "name": "Updated Product Catalog", "description": "Revised product information and specifications" }' \ https://api.xpander.ai/v1/knowledge/ ``` ## Example Response ```json theme={"dark"} { "id": "", "name": "Product Catalog v2", "description": "Updated product information and pricing details", "type": "managed", "organization_id": "", "agent_id": null, "total_documents": 0 } ``` ## Notes * All fields in the request body are optional * Fields not provided in the request will retain their existing values * Returns 404 if the knowledge base is not found # Get Database Connection Source: https://docs.xpander.ai/api-reference/v1/misc/get-database GET /v1/misc/db Get PostgreSQL database connection string for your organization Retrieve the PostgreSQL database connection details for your organization. This provides direct access to your organization's database instance for custom analytics, integrations, and data management. ## Response Database project identifier Database project name (typically `org_[organization_id]`) Your organization UUID Database connection details Complete PostgreSQL connection string with credentials Format: `postgresql://:@/?` ## Example Request ```bash theme={"dark"} curl -X GET -H "x-api-key: " \ https://api.xpander.ai/v1/misc/db ``` ## Example Response ```json theme={"dark"} { "id": "still-meadow-47437464", "name": "org_f47ac10b-58cc-4372-a567-0e02b2c3d479", "organization_id": "", "connection_uri": { "uri": "postgresql://:@/?sslmode=require" } } ``` ## Usage Examples ### Python (psycopg2) ```python theme={"dark"} import psycopg2 import requests # Get connection string response = requests.get( "https://api.xpander.ai/v1/misc/db", headers={"x-api-key": ""} ) connection_uri = response.json()["connection_uri"]["uri"] # Connect to database conn = psycopg2.connect(connection_uri) cursor = conn.cursor() # Query data cursor.execute("SELECT * FROM agents LIMIT 10") results = cursor.fetchall() cursor.close() conn.close() ``` ### Node.js (pg) ```javascript theme={"dark"} const fetch = require('node-fetch'); const { Client } = require('pg'); // Get connection string const response = await fetch('https://api.xpander.ai/v1/misc/db', { headers: { 'x-api-key': '' } }); const { connection_uri } = await response.json(); // Connect to database const client = new Client({ connectionString: connection_uri.uri }); await client.connect(); // Query data const result = await client.query('SELECT * FROM agents LIMIT 10'); console.log(result.rows); await client.end(); ``` ### CLI (psql) ```bash theme={"dark"} # Get connection string and connect psql "$(curl -s -H 'x-api-key: ' \ https://api.xpander.ai/v1/misc/db | jq -r '.connection_uri.uri')" ``` ## Database Schema Your organization database contains tables for: * **agents** - Agent configurations and metadata * **tasks** - Task execution records * **knowledge\_bases** - Knowledge base metadata * **documents** - Document records and processing status * **users** - User information and permissions * **organization** - Organization settings and data * And more... ## Security Notes * The connection string includes credentials - keep it secure * Store the connection string as an environment variable, never in version control * Use HTTPS only when retrieving connection strings * The database requires SSL connections (sslmode=require) * Be cautious with write operations to avoid accidental data modification * Regularly rotate credentials in your organization settings ## Use Cases * **Custom analytics** - Query task and agent data directly for reporting * **Data export** - Extract data for external analysis and backup * **Business intelligence** - Connect BI tools like Tableau, Metabase, Power BI * **Integration** - Build custom integrations with third-party systems * **Automation** - Create automated data processing pipelines * **Advanced queries** - Perform complex SQL queries not available via REST API ## Notes * This is a Neon PostgreSQL serverless database * Connection pooling is handled automatically * Database is located in AWS us-west-2 region * SSL connections are required for security * Connection credentials are organization-specific and should not be shared # List LLM Models Source: https://docs.xpander.ai/api-reference/v1/misc/list-llm-models GET /v1/misc/llm_providers/{provider_identifier}/models Returns available models for a specific LLM provider List available models for a specific LLM provider. Use the `model_id` value as the agent's `model_name` field when creating or updating an agent. ## Path Parameters The provider's `internal_identifier` from [List LLM Providers](/api-reference/v1/misc/list-llm-providers) (e.g., `openai`, `anthropic`) ## Response Returns an array of `LLMModelItem` objects. Model identifier — use this as the `model_name` field when creating/updating agents Human-friendly model name Model tier level (1 = standard, higher = premium) Brief description of the model's capabilities ## Example Request ```bash theme={"dark"} curl -X GET -H "x-api-key: " \ "https://api.xpander.ai/v1/misc/llm_providers/openai/models" ``` ## Notes * Returns `404` if the provider identifier is not found * Use the `model_id` value as the agent's `model_name` field * Models are organized by tier — higher tiers indicate more capable (and more expensive) models # List LLM Providers Source: https://docs.xpander.ai/api-reference/v1/misc/list-llm-providers GET /v1/misc/llm_providers Returns a list of available LLM providers List all available LLM providers. Use the provider's `internal_identifier` with [List LLM Models](/api-reference/v1/misc/list-llm-models) to retrieve available models. ## Response Returns an array of `LLMProviderItem` objects. Provider unique identifier Provider display name (e.g., "OpenAI", "Anthropic") Internal identifier used in API calls (e.g., `openai`, `anthropic`). Use this value as `model_provider` when creating or updating agents. URL to the provider's logo image Brief description of the provider ## Example Request ```bash theme={"dark"} curl -X GET -H "x-api-key: " \ "https://api.xpander.ai/v1/misc/llm_providers" ``` ## Notes * Use the `internal_identifier` value as the `model_provider` field when creating or updating agents * To see available models for a provider, use [List LLM Models](/api-reference/v1/misc/list-llm-models) with the `internal_identifier` # Delete Task Source: https://docs.xpander.ai/api-reference/v1/tasks/delete-task DELETE /v1/tasks/{task_id} Delete a task and its associated data Delete a task by ID. Running tasks will be cancelled before deletion, and all associated data including results and conversation history will be permanently removed. ## Path Parameters Unique identifier of the task to delete (UUID format) ## Response Returns `204 No Content` on successful deletion (empty response body). ## Example Request ```bash theme={"dark"} curl -X DELETE -H "x-api-key: " \ "https://api.xpander.ai/v1/tasks/" ``` ## Response Status Codes | Status | Meaning | | ------ | -------------------------------------------------- | | 204 | Task deleted successfully | | 404 | Task not found | | 401 | Unauthorized (invalid API key) | | 403 | Forbidden (task belongs to different organization) | ## Important Notes * **Permanent deletion** - This action cannot be undone * **Running tasks** - Will be cancelled before deletion * **Data removal** - Results, conversation history, and all associated data are removed * **Sub-tasks** - All sub-tasks are also deleted ## Example with Error Handling ```bash theme={"dark"} TASK_ID="" RESPONSE=$(curl -w "\n%{http_code}" -X DELETE \ -H "x-api-key: " \ "https://api.xpander.ai/v1/tasks/$TASK_ID") HTTP_CODE=$(echo "$RESPONSE" | tail -n1) if [[ $HTTP_CODE == "204" ]]; then echo "Task deleted successfully" elif [[ $HTTP_CODE == "404" ]]; then echo "Task not found" else echo "Error: $HTTP_CODE" fi ``` ## Use Cases * **Clean up completed tasks** - Remove old task data to save storage * **Cancel running tasks** - Stop a task that's in progress * **Manage sensitive data** - Delete tasks containing sensitive information * **Maintain organization** - Remove test or failed tasks # Get Task LLM Usage Source: https://docs.xpander.ai/api-reference/v1/tasks/get-llm-usage GET /v1/tasks/{task_id}/llm_usage Get LLM token usage for a specific task Retrieve LLM token usage statistics for a specific task, including input/output token counts and the number of tool actions performed. ## Path Parameters Unique identifier of the task (UUID format) ## Response Unique identifier of the task Total number of LLM tokens consumed (input + output) Number of input (prompt) tokens consumed Number of output (completion) tokens generated Number of tool actions performed during the task Whether the task used a Bring Your Own Key (BYOK) model configuration Estimated USD cost for non-BYOK executions in this task, rounded to 5 decimal places. `0.0` means no billable usage (empty task or fully BYOK). ## Example Request ```bash theme={"dark"} curl -X GET -H "x-api-key: " \ "https://api.xpander.ai/v1/tasks//llm_usage" ``` ## Example Response ```json theme={"dark"} { "task_id": "e6cf93db-30c7-471b-a1a9-5051a2c9e4ba", "tokens": 3842, "input_tokens": 1520, "output_tokens": 2322, "actions": 4, "is_byok": false, "cost": 0.01284 } ``` ## Use Cases * **Track token consumption** - Monitor LLM token usage for individual tasks * **Cost tracking** - `cost` is returned directly in USD, rounded to 5 decimal places (excludes BYOK executions) * **Usage auditing** - Review resource consumption across tasks * **BYOK tracking** - Identify which tasks ran with your own API keys vs. platform-provided keys # Get Task Source: https://docs.xpander.ai/api-reference/v1/tasks/get-task GET /v1/tasks/{task_id} Retrieve detailed information about a specific task by its unique identifier Get complete details about a task/thread record including its current status, latest input, latest result, and execution timing. This endpoint is essential for polling async tasks and for inspecting the latest turn of a continued conversation. ## Path Parameters Unique identifier of the task to retrieve (UUID format) ## Response Task/thread identifier. Reuse this as `id` in later invokes to continue the same conversation. UUID of the agent that executed this task UUID of the organization that owns this task Latest input stored on this task/thread record Text message or query Array of file references (if any) User information (nullable) Current task status: `pending`, `executing`, `paused`, `error`, `failed`, `completed`, or `stopped` Latest task result. This is usually plain text or markdown. Only parse it as JSON if you explicitly requested JSON/structured output. Output format for the latest result, such as `markdown` or `json` ISO 8601 timestamp of when the task was created ISO 8601 timestamp of when execution began (null if not started) ISO 8601 timestamp of when the task finished (null if still running) Source of the task creation: `api`, `sdk`, `dashboard`, `webhook` Whether the task used event streaming Array of sub-task UUIDs spawned by this task UUID of parent task if this is a sub-task (null otherwise) Additional metadata (nullable) In a multi-turn conversation, this endpoint shows the latest input and latest result for the reused task/thread ID. Use [Get Task Thread](/api-reference/v1/tasks/get-thread) or [Get Task Thread (Full)](/api-reference/v1/tasks/get-thread-full) for the full message history. ## Example Request ```bash theme={"dark"} curl -X GET -H "x-api-key: " \ "https://api.xpander.ai/v1/tasks/" ``` ## Example Response ```json theme={"dark"} { "id": "fbd08e4d-cfa7-4838-b6e6-e51855ac2ba3", "agent_id": "", "organization_id": "", "input": { "text": "Reply with exactly SECOND", "files": [], "user": null }, "status": "completed", "created_at": "2026-03-23T00:45:26.965823Z", "started_at": null, "finished_at": "2026-03-23T00:45:30.532954Z", "result": "SECOND", "source": "api", "output_format": "markdown", "events_streaming": true, "sub_executions": [], "parent_execution": null, "payload_extension": null } ``` ## Extracting Results For normal text or markdown responses: ```bash theme={"dark"} curl -X GET -H "x-api-key: " \ "https://api.xpander.ai/v1/tasks/" | jq -r '.result' ``` Only use `fromjson` when you explicitly requested JSON output: ```bash theme={"dark"} curl -X GET -H "x-api-key: " \ "https://api.xpander.ai/v1/tasks/" | jq '.result | fromjson' ``` ## Status Polling Pattern For async workflows, poll until `status` is no longer `pending` or `executing`: ```bash theme={"dark"} # Poll every 2 seconds until task completes while true; do TASK=$(curl -s -H "x-api-key: " \ "https://api.xpander.ai/v1/tasks/") STATUS=$(echo $TASK | jq -r '.status') if [[ $STATUS == "completed" ]]; then echo $TASK | jq -r '.result' break fi sleep 2 done ``` ## Use Cases * **Retrieve task results** - Get final output after async execution * **Check execution status** - Monitor if task is still executing * **Track timing** - See `created_at`, `started_at`, `finished_at` for performance analysis * **Get latest-turn details** - Review the most recent input and output for a continued conversation # Get Task Thread Source: https://docs.xpander.ai/api-reference/v1/tasks/get-thread GET /v1/tasks/{task_id}/thread Get task conversation thread with user and assistant messages Retrieve the root conversation thread for a task/thread ID as a simple array. When you continue a conversation by passing the same invocation `id`, the new turns are appended here under that same task/thread ID. ## Path Parameters Unique identifier of the task (UUID format) ## Response Returns an array of message objects representing the root conversation: Array of conversation messages Unique message identifier (UUID) Message role: `user` or `assistant` Message content text Unix timestamp of message creation ## Example Request ```bash theme={"dark"} curl -X GET -H "x-api-key: " \ "https://api.xpander.ai/v1/tasks//thread" ``` ## Example Response Multi-turn conversation thread: ```json theme={"dark"} [ { "id": "_user_1", "role": "user", "content": "Reply with exactly FIRST", "created_at": 1774226722 }, { "id": "_agent_1", "role": "assistant", "content": "FIRST", "created_at": 1774226726 }, { "id": "_user_2", "role": "user", "content": "Reply with exactly SECOND", "created_at": 1774226726 }, { "id": "_agent_2", "role": "assistant", "content": "SECOND", "created_at": 1774226730 } ] ``` ## Parsing Examples **Pretty print the conversation:** ```bash theme={"dark"} curl -s -H "x-api-key: " \ "https://api.xpander.ai/v1/tasks//thread" | \ jq '.[] | "\(.role): \(.content)"' ``` **Count messages in the thread:** ```bash theme={"dark"} curl -s -H "x-api-key: " \ "https://api.xpander.ai/v1/tasks//thread" | \ jq 'length' ``` **Extract the latest assistant response:** ```bash theme={"dark"} curl -s -H "x-api-key: " \ "https://api.xpander.ai/v1/tasks//thread" | \ jq '[.[] | select(.role == "assistant")][-1].content' ``` ## Use Cases * **View conversation history** - See the complete interaction between user and agent * **Review agent responses** - Understand what the agent said and its reasoning * **Track token usage** - Monitor LLM API costs per message * **Audit conversations** - Review interaction history for compliance ## Notes * Returns only the root task's messages (excludes sub-task buckets) * Continuing a conversation with the same invocation `id` appends new turns to this array * For multi-agent workflows with sub-tasks, use [Get Task Thread (Full)](/api-reference/v1/tasks/get-thread-full) * Messages are ordered chronologically by creation time # Get Task Thread (Full) Source: https://docs.xpander.ai/api-reference/v1/tasks/get-thread-full GET /v1/tasks/{task_id}/thread/full Get complete conversation thread including all sub-task messages and tool calls Retrieve the complete conversation thread for a task/thread ID, including the root conversation and any sub-task message buckets. This is the authoritative message-history endpoint for multi-turn conversations continued with the same invocation `id`. ## Path Parameters Unique identifier of the task (UUID format) ## Response Returns an object where `root` contains the main conversation and additional keys may appear for sub-task IDs: Array of messages from the root task Unique message identifier (UUID) Message role: `user`, `assistant`, `system`, or `tool` Message content text Unix timestamp of message creation For each sub-task, an array of messages with the same structure as `root`. The key is the UUID of the sub-task. ## Example Request ```bash theme={"dark"} curl -X GET -H "x-api-key: " \ "https://api.xpander.ai/v1/tasks//thread/full" ``` ## Example Response ```json theme={"dark"} { "root": [ { "id": "_user_1", "role": "user", "content": "Reply with exactly FIRST", "created_at": 1774226722 }, { "id": "_agent_1", "role": "assistant", "content": "FIRST", "created_at": 1774226726 }, { "id": "_user_2", "role": "user", "content": "Reply with exactly SECOND", "created_at": 1774226726 }, { "id": "_agent_2", "role": "assistant", "content": "SECOND", "created_at": 1774226730 } ] } ``` ## Parsing Examples **Get all task IDs (root + sub-tasks):** ```bash theme={"dark"} curl -s -H "x-api-key: " \ "https://api.xpander.ai/v1/tasks//thread/full" | \ jq 'keys' ``` **Count messages in each task:** ```bash theme={"dark"} curl -s -H "x-api-key: " \ "https://api.xpander.ai/v1/tasks//thread/full" | \ jq 'map_values(length)' ``` **Print the root conversation:** ```bash theme={"dark"} curl -s -H "x-api-key: " \ "https://api.xpander.ai/v1/tasks//thread/full" | \ jq '.root[] | "\(.role): \(.content)"' ``` **Flatten all messages across root and sub-tasks:** ```bash theme={"dark"} curl -s -H "x-api-key: " \ "https://api.xpander.ai/v1/tasks//thread/full" | \ jq 'to_entries | map(.value[]) | .[] | "\(.role): \(.content)"' ``` ## Use Cases * **Debug multi-agent workflows** - See the complete execution tree with all sub-agents * **Analyze token usage** - Track token consumption across all sub-tasks and calculate costs * **Audit conversations** - Review complete interaction history including internal routing * **Performance analysis** - Measure response times and token efficiency per sub-task * **Troubleshoot failures** - See all tool calls and system messages that led to errors ## Comparison with /thread Endpoint | Feature | /thread | /thread/full | | ---------------------------- | ------- | --------------------------------------- | | Root task messages | ✅ | ✅ | | Multi-turn root conversation | ✅ | ✅ | | Sub-task message buckets | ❌ | ✅ | | Response structure | Array | Object keyed by `root` and sub-task IDs | ## Notes * The `root` key contains the main conversation for the task/thread ID you requested * Continuing a conversation with the same invocation `id` appends new turns to `root` * Multi-agent or delegated runs can add extra keys for sub-task IDs * Messages are ordered chronologically within each task bucket ## See Also * [Get Task Thread](/api-reference/v1/tasks/get-thread) - Get the root task thread only * [Get Task](/api-reference/v1/tasks/get-task) - Get the latest task state and result * [List Tasks](/api-reference/v1/tasks/list-tasks) - List all tasks # List Tasks Source: https://docs.xpander.ai/api-reference/v1/tasks/list-tasks GET /v1/tasks Get paginated list of tasks with optional filtering by status, agent, or date range Retrieve a paginated list of tasks with optional filtering by status, agent ID, or creation date. Useful for monitoring task execution across your organization or for specific agents. ## Query Parameters Page number (starting from 1) Items per page (maximum 50) Filter by user ID who created the task Filter by specific agent UUID Filter by parent task ID (for sub-tasks) Filter by triggering agent ID (parent calling agent in multi-agent workflows) Filter by task status: `pending`, `executing`, `paused`, `error`, `failed`, `completed`, `stopped` Filter by internal task processing status Filter tasks created on or after this date (ISO 8601, e.g., `2026-02-01T00:00:00Z`) Filter tasks created on or before this date (ISO 8601) ## Response Array of task objects Unique identifier for the task (UUID format) UUID of the agent that executed this task UUID of the user who created the task (null if created via API) UUID of parent task if this is a subtask (null otherwise) UUID of agent that triggered this task (null if not triggered by agent) UUID of the organization that owns this task Current task status: `queued`, `running`, `completed`, `failed`, `cancelled` ISO 8601 timestamp of task creation ISO 8601 timestamp of last update Source that created the task (e.g., `sdk`, `api`, `webhook`) Task execution result as JSON string (present when completed) Task title or description (nullable) Total number of tasks matching the filter across all pages Current page number Number of items returned per page Total number of pages available ## Example Requests ```bash theme={"dark"} # List all tasks (first page) curl -X GET -H "x-api-key: " \ "https://api.xpander.ai/v1/tasks?page=1&per_page=10" # Filter by status curl -X GET -H "x-api-key: " \ "https://api.xpander.ai/v1/tasks?status=completed&page=1&per_page=10" # Filter by agent curl -X GET -H "x-api-key: " \ "https://api.xpander.ai/v1/tasks?agent_id=&page=1" # Filter by date range curl -X GET -H "x-api-key: " \ "https://api.xpander.ai/v1/tasks?from_date=2026-02-01T00:00:00Z&to_date=2026-02-07T23:59:59Z" ``` ## Example Response ```json theme={"dark"} { "items": [ { "id": "81250b20-e9d7-4b3b-9995-07dc72b4bb59", "agent_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890", "user_id": null, "parent_task_id": null, "triggering_agent_id": null, "organization_id": "f47ac10b-58cc-4372-a567-0e02b2c3d479", "status": "completed", "created_at": "2026-02-07T02:13:27.228497Z", "updated_at": "2026-02-07T02:13:41.541072Z", "source_node_type": "sdk", "result": "{\"name\":\"xpander.ai\",\"notes\":\"Full-stack agent platform...\"}", "title": "What is xpander.ai?" } ], "total": 4300, "page": 1, "per_page": 2, "total_pages": 2150 } ``` ## Use Cases * **Monitor task volume** - Track total tasks and completion rates * **Filter by agent** - See tasks for a specific agent * **Find completed work** - Retrieve only successful task executions * **Track recent activity** - Filter by creation date range ## See Also * [Get Task](/api-reference/v1/tasks/get-task) - Get detailed information about a specific task * [Stop Task](/api-reference/v1/tasks/stop-task) - Cancel a running task * [Delete Task](/api-reference/v1/tasks/delete-task) - Permanently remove a task and its data * [Get Task Thread](/api-reference/v1/tasks/get-thread) - Get the conversation history of a task # Stop Task Source: https://docs.xpander.ai/api-reference/v1/tasks/stop-task POST /v1/tasks/{task_id}/stop Stop a running task Cancel a running task. Sends a stop signal to the worker executing the task, marks the execution as `stopped`, and sets `is_manually_stopped: true`. Returns the updated task record. The endpoint is idempotent: calling it on a task that is already in a terminal state (`completed`, `failed`, `stopped`) returns the current execution unchanged. ## Path Parameters Unique identifier of the task to stop (UUID format) ## Response Returns the updated [Agent Execution](/api-reference/v1/tasks/get-task) object with `status` set to `stopped` and `is_manually_stopped` set to `true`. ## Example Request ```bash theme={"dark"} curl -X POST -H "x-api-key: " \ "https://api.xpander.ai/v1/tasks//stop" ``` ## Example Response ```json theme={"dark"} { "id": "fbd08e4d-cfa7-4838-b6e6-e51855ac2ba3", "agent_id": "", "organization_id": "", "status": "stopped", "is_manually_stopped": true, "created_at": "2026-05-13T10:12:04.123456Z", "started_at": "2026-05-13T10:12:05.001234Z", "finished_at": "2026-05-13T10:12:42.998877Z", "result": null, "source": "api" } ``` ## Response Status Codes | Status | Meaning | | ------ | ---------------------------------------------------------- | | 200 | Stop signal accepted (or task already in a terminal state) | | 401 | Unauthorized (invalid API key) | | 403 | Forbidden (task belongs to a different organization) | | 404 | Task not found | | 422 | Validation error (malformed `task_id`) | ## Important Notes * **Idempotent** - Tasks already in `completed`, `failed`, or `stopped` are returned unchanged * **Asynchronous** - The worker may take a few seconds to observe the stop signal and exit cleanly. Poll [Get Task](/api-reference/v1/tasks/get-task) until `status` becomes `stopped` * **Self-hosted environments** - For agents running in a self-hosted environment, the stop request is routed cross-environment via the asset-command channel * **Manual flag** - `is_manually_stopped: true` distinguishes user-initiated cancels from system-side terminations ## Example: Stop and confirm ```bash theme={"dark"} TASK_ID="" curl -s -X POST -H "x-api-key: " \ "https://api.xpander.ai/v1/tasks/$TASK_ID/stop" > /dev/null while true; do STATUS=$(curl -s -H "x-api-key: " \ "https://api.xpander.ai/v1/tasks/$TASK_ID" | jq -r '.status') if [[ $STATUS == "stopped" || $STATUS == "completed" || $STATUS == "failed" ]]; then echo "Final status: $STATUS" break fi sleep 2 done ``` ## Use Cases * **Cancel a runaway agent** - Halt an execution that is consuming too much time or tokens * **User-initiated cancel** - Wire a "Stop" button in your UI to this endpoint * **Abort long-running tasks** - Free up worker capacity when a task is no longer needed * **Recover from stuck tasks** - Force-terminate executions that are not progressing # Connect Connector Source: https://docs.xpander.ai/api-reference/v1/tools/connect-connector POST /v1/tools/connectors/{connector_id}/connect Create a connection to a connector. For OAuth2 connectors, returns an oauth2_required response with a connector_page_url to complete browser auth. Find the `connector_id` in the connector page URL at `chat.xpander.ai/connectors/{connector_id}`, or via [List Tools](/api-reference/v1/tools/list-tools) with `?type=connector&query=...`. For API-key connectors, the connection is created immediately and its `id` is your **`connection_id`** for [List Connector Operations](/api-reference/v1/tools/list-connector-operations) and [Invoke Connector Operation](/api-reference/v1/tools/invoke-connector-operation). For OAuth2 connectors, the response is `oauth2_required` with a `connector_page_url` — open it in a browser to finish authentication, then fetch the new connection's `id` from [List Tools](/api-reference/v1/tools/list-tools). # Get Connector Operation Schema Source: https://docs.xpander.ai/api-reference/v1/tools/get-connector-operation-schema GET /v1/tools/connectors/{connector_id}/connections/{connection_id}/{operation_id}/schema Get an operation's input/output schema. input is a JSON schema grouping query_params/path_params/body_params - the same structure Invoke Connector Operation accepts; output is the operation's success (2xx application/json) response schema. All $ref references are resolved inline. The response's `input` field is a JSON schema grouping `query_params`, `path_params`, and `body_params` — the exact structure [Invoke Connector Operation](/api-reference/v1/tools/invoke-connector-operation) accepts, so you can inspect here and invoke with confidence. `output` is the operation's success (2xx `application/json`) response schema. All `$ref` references are resolved inline. `operation_id` accepts the operation's `id` or `operationId` from [List Connector Operations](/api-reference/v1/tools/list-connector-operations). Pass `_` as `connector_id` to resolve it from the connection. # Invoke Connector Operation Source: https://docs.xpander.ai/api-reference/v1/tools/invoke-connector-operation POST /v1/tools/connectors/{connector_id}/connections/{connection_id}/{operation_id} Invoke a connector operation on a connection directly - no agent or task required. The response is the target API's response. New to connector invocation? Follow the end-to-end walkthrough in [Invoke a Connector via API](/api-reference/invoke-connector-api) — it shows how to find each of the three IDs this endpoint needs. You need three path IDs: the `connector_id` (shown in the connector page URL at `chat.xpander.ai/connectors/{connector_id}`), the `connection_id` (your org's authenticated connection — find it in `connections[].id` from [List Tools](/api-reference/v1/tools/list-tools)), and the `operation_id` (from [List Connector Operations](/api-reference/v1/tools/list-connector-operations) — its `id` or `operationId` both work). Pass `_` as `connector_id` to resolve it from the connection. The body follows the same `RequestPayload` schema the agent-controller uses: `body_params` (request body), `query_params`, `path_params` (by name), and `headers` (extra headers for the target API). All four are optional — send only what the operation needs. Use [Get Connector Operation Schema](/api-reference/v1/tools/get-connector-operation-schema) to inspect the expected inputs first; its `input` schema uses exactly these three groups. The operation runs with its spec-defined HTTP method regardless of this POST, the connection's stored credentials are applied automatically, and the response is the target API's response, passed through unchanged. Times out after 300s. # List Connector Operations Source: https://docs.xpander.ai/api-reference/v1/tools/list-connector-operations GET /v1/tools/connectors/{connector_id}/operations List (or search) a connection's operations. Use an operation's id as operation_id when attaching it to an agent. Connections are organization-scoped — pass the `connection_id` (as a **query parameter**) of a connection you own. Find it in `connections[].id` from [List Tools](/api-reference/v1/tools/list-tools); it is a different UUID from the `connector_id` in the path. Each returned operation has two usable identifiers: `id` (a catalog ID) and `operationId` (a human-readable name like `FirecrawlScrapingServiceExtractWebpageContent`). Either one works as the `operation_id` when calling [Invoke Connector Operation](/api-reference/v1/tools/invoke-connector-operation) or when attaching the operation to an agent. Use `?query=` to fuzzy-search operations by name or description. # List Tools Source: https://docs.xpander.ai/api-reference/v1/tools/list-tools GET /v1/tools Unified catalog of attachable tools: connectors, agents, workflows, custom functions, and MCP servers. Discover everything you can attach to an agent or workflow in one place. Pass `?type=` to scope the request to one kind — `connector`, `agent`, `workflow` or `mcp` — and optionally `?query=` to narrow it further. MCP entries come from your organization's MCP registry. For connectors, each item carries the two IDs you need to invoke operations directly: `id` is the **`connector_id`**, and `connections[].id` is the **`connection_id`**. An empty `connections` array means the connector isn't connected yet — create a connection with [Connect Connector](/api-reference/v1/tools/connect-connector) first. See [Invoke a Connector via API](/api-reference/invoke-connector-api) for the full flow. # Search Tools Source: https://docs.xpander.ai/api-reference/v1/tools/search-tools GET /v1/tools/search Fuzzy search the unified tool catalog by name or description. Fuzzy-search the tool catalog by name or description. Pass `type` alongside `query` to scope the search to one kind, e.g. `?query=firecrawl&type=connector`. Connector results include `connections[].id` — the `connection_id` needed by [List Connector Operations](/api-reference/v1/tools/list-connector-operations) and [Invoke Connector Operation](/api-reference/v1/tools/invoke-connector-operation). # Create Workflow Source: https://docs.xpander.ai/api-reference/v1/workflows/create-workflow POST /v1/workflows Create a new multi-step agentic workflow with a visual canvas of nodes Create a new workflow — a deterministic, multi-step pipeline where AI agents, tools, and logic nodes are wired together on a canvas. Only `name` is required — all other fields are optional. Data flows left-to-right through the pipeline: from a START trigger, through your processing nodes, to an END output. ## Request Body Display name for the workflow Description of the workflow's purpose Emoji icon for the workflow LLM provider: `openai` (default), `anthropic`, etc. Specific model version Reasoning effort level for the orchestrator LLM System instructions for the orchestrator Array of role descriptions Array of goal descriptions General instructions text Array of node definitions that make up the workflow canvas. Each node is powered by an AI agent (except Code nodes). Node types include: * `pointer` — Invokes one of your xpander AI agents with its full tool set and memory * `classifier` — An LLM that classifies, labels, or routes data based on natural language instructions * `parallel` — Runs multiple branches simultaneously * `code` — Executes custom code for deterministic logic (the only node that doesn't use an LLM) * `guardrail` — An AI judge that evaluates a natural language condition and returns Pass/Fail * `summarizer` — An agent that answers specific questions from large payloads * `wait` — Pauses execution until a condition is met (webhook callback or human approval) * `send_to_end` — Skips remaining nodes and routes directly to the END block Task-level strategies for retry, stop conditions, and iteration Notification configuration (Slack, email, webhook) for workflow events Output format: `text` or `json` JSON schema for structured output when `output_format` is `json` Natural-language description of the desired output Deployment infrastructure: `serverless` (default) `personal` or `organizational` (default) Source node configurations (e.g., Slack, web UI triggers) ## Response Returns the created `WorkflowResponse` object with generated ID and webhook URL. ## Example Request ```bash theme={"dark"} curl -X POST "https://api.xpander.ai/v1/workflows" \ -H "Content-Type: application/json" \ -H "x-api-key: " \ -d '{ "name": "Customer Onboarding Workflow", "description": "Orchestrates the customer onboarding process", "model_provider": "openai", "model_name": "gpt-4o", "instructions": { "role": ["Workflow orchestrator"], "goal": ["Coordinate onboarding steps efficiently"], "general": "Route tasks to the appropriate sub-agents" } }' ``` ## Notes * The workflow is created with `type: orchestration` automatically * Every node (except Code) is powered by an AI agent — you write natural language instructions, not field mappings * Nodes auto-connect: data flows from each node's output to the next node's input as context * Deploy the workflow using [Deploy Workflow](/api-reference/v1/workflows/deploy-workflow) after configuration * See the [Workflows user guide](/user-guide/build/workflow) for details on the visual canvas and node types # Delete Workflow Source: https://docs.xpander.ai/api-reference/v1/workflows/delete-workflow DELETE /v1/workflows/{workflow_id} Permanently delete a workflow and all associated resources Permanently delete a workflow, its node graph, and all associated resources. This operation cannot be undone. ## Path Parameters Unique identifier of the workflow to delete (UUID) ## Response Returns HTTP `202 Accepted` on successful deletion. ## Example Request ```bash theme={"dark"} curl -X DELETE -H "x-api-key: " \ "https://api.xpander.ai/v1/workflows/" ``` ## Notes * This operation is permanent and cannot be undone * Active tasks may be terminated # Deploy Workflow Source: https://docs.xpander.ai/api-reference/v1/workflows/deploy-workflow PUT /v1/workflows/{workflow_id} Deploy a workflow to make it active and available for execution Deploy a workflow to activate it for task execution. Validates the node graph, provisions necessary resources, and increments the version number. After deployment, the workflow is ready to receive triggers (webhook, API, chat, or schedule). ## Path Parameters Unique identifier of the workflow (UUID) ## Response Returns the deployed `WorkflowResponse` object with updated status. ## Example Request ```bash theme={"dark"} curl -X PUT -H "x-api-key: " \ "https://api.xpander.ai/v1/workflows/" ``` ## Notes * Validates the node graph before deploying * Increments the workflow version number * The workflow must have a valid canvas with properly connected nodes to deploy successfully * After deployment, all four trigger types become available (webhook, API, chat, schedule) # Get Workflow Source: https://docs.xpander.ai/api-reference/v1/workflows/get-workflow GET /v1/workflows/{workflow_id} Retrieve detailed information about a specific workflow by its unique identifier Get complete details for a specific workflow, including its full node graph, model settings, instructions, and deployment status. The `orchestration_nodes` array represents the canvas layout — each node is a step in the pipeline (Agent, Action, Classifier, Guardrail, etc.). ## Path Parameters Unique identifier of the workflow (UUID) ## Response Returns the full `WorkflowResponse` object with all configuration details including the node graph, trigger settings, notification configuration, and task-level strategies. ## Example Request ```bash theme={"dark"} curl -X GET -H "x-api-key: " \ "https://api.xpander.ai/v1/workflows/" ``` ## Notes * Returns `404` if the ID belongs to a regular agent (not a workflow) * The `orchestration_nodes` array contains the full canvas graph — each node includes its type, instructions, and connections to other nodes * Node types include: `pointer` (Agent), `classifier`, `parallel`, `code`, `guardrail`, `summarizer`, `wait`, `send_to_end` # Invoke Workflow (Async) Source: https://docs.xpander.ai/api-reference/v1/workflows/invoke-async POST /v1/workflows/{workflow_id}/invoke/async Invoke a workflow asynchronously. Returns immediately with task ID. Invoke a workflow asynchronously. Returns immediately with a task ID while the pipeline executes in the background. Poll [Get Task](/api-reference/v1/tasks/get-task) to check when results are ready. ## Path Parameters Workflow ID (UUID) ## Query Parameters The workflow version to invoke. Defaults to the latest deployed version. ## Request Body Same as [Invoke Workflow (Sync)](/api-reference/v1/workflows/invoke-sync) — see that page for full request body documentation. ## Response Task ID — use this to poll for status and results Initial status, typically `pending` or `executing` ## Example Request ```bash theme={"dark"} curl -X POST "https://api.xpander.ai/v1/workflows//invoke/async" \ -H "Content-Type: application/json" \ -H "x-api-key: " \ -d '{"input": {"text": "Run the full analysis pipeline"}}' ``` ## Notes * Returns immediately without waiting for the pipeline to complete * Use [Get Task](/api-reference/v1/tasks/get-task) to poll for results * Ideal for multi-step workflows where the pipeline takes time to execute across all nodes # Invoke Workflow (Stream) Source: https://docs.xpander.ai/api-reference/v1/workflows/invoke-stream POST /v1/workflows/{workflow_id}/invoke/stream Invoke a workflow with real-time streaming. Returns Server-Sent Events (SSE). Invoke a workflow with real-time streaming via Server-Sent Events (SSE). Receive live updates as the pipeline progresses through each node on the canvas — including tool calls, agent reasoning, sub-agent triggers, and the final result. ## Path Parameters Workflow ID (UUID) ## Query Parameters The workflow version to invoke. Defaults to the latest deployed version. ## Request Body Same as [Invoke Workflow (Sync)](/api-reference/v1/workflows/invoke-sync) — see that page for full request body documentation. ## Response Returns a `text/event-stream` response with Server-Sent Events. Each event contains a JSON payload with task update information. Events are sent as the workflow executes, including status changes, intermediate results, and the final `TaskFinished` event. ## Example Request ```bash theme={"dark"} curl -N -X POST "https://api.xpander.ai/v1/workflows//invoke/stream" \ -H "Content-Type: application/json" \ -H "x-api-key: " \ -d '{"input": {"text": "Generate a comprehensive report"}}' ``` ## Notes * The stream ends with a `TaskFinished` event type * Each SSE event is a `data:` line containing a JSON object * Use `Cache-Control: no-cache` and `Connection: keep-alive` headers for best results * Ideal for building real-time UIs that show pipeline progress across nodes # Invoke Workflow (Sync) Source: https://docs.xpander.ai/api-reference/v1/workflows/invoke-sync POST /v1/workflows/{workflow_id}/invoke Invoke a workflow and wait for completion. Returns the final result. Invoke a workflow synchronously. The request blocks until the entire pipeline completes — data flows through each node on the canvas from START to END, and the final result is returned. For longer-running workflows, use [Invoke Workflow (Async)](/api-reference/v1/workflows/invoke-async) or [Invoke Workflow (Stream)](/api-reference/v1/workflows/invoke-stream) to track progress in real time. ## Path Parameters Workflow ID (UUID) ## Query Parameters The workflow version to invoke. Defaults to the latest deployed version. ## Request Body The message or prompt to send to the workflow URLs of files for the workflow to process Identity of the end user invoking the workflow User email First name Last name External user ID Thread ID for multi-turn conversations. Pass the `id` from a previous task's response to continue the same conversation. Controls reasoning depth: `default` or `harder` Additional instructions for this invocation only Natural-language description of the desired output ## Response Task/thread ID — pass this back to continue the conversation `completed`, `failed`, `error`, or `stopped` The workflow's final response ## Example Request ```bash theme={"dark"} curl -X POST "https://api.xpander.ai/v1/workflows//invoke" \ -H "Content-Type: application/json" \ -H "x-api-key: " \ -d '{"input": {"text": "Process this customer onboarding request"}}' ``` # List Workflows Source: https://docs.xpander.ai/api-reference/v1/workflows/list-workflows GET /v1/workflows Retrieve a paginated list of workflows Retrieve a paginated list of workflows in your organization. Workflows are a visual orchestration layer for your AI agents — deterministic, multi-step pipelines where you arrange agents, tools, and logic nodes on a canvas to control execution order, branching, and data flow. In the API, workflows are represented as agents with `type: "orchestration"`. Every node in a workflow is powered by an AI agent, so the execution path is predictable but the intelligence at each step is adaptive. ## Query Parameters Page number (starting from 1) Items per page (maximum 50) ## Response Array of workflow objects Unique identifier for the workflow (UUID) Display name of the workflow Brief description of the workflow's purpose Emoji icon representing the workflow Current deployment status: `ACTIVE` or `INACTIVE` Organization UUID this workflow belongs to Always `orchestration` for workflows Deployment method: `serverless` LLM provider (e.g., `openai`, `anthropic`) Specific model version The workflow's node graph — each node represents a step on the canvas (Agent, Classifier, Action, Guardrail, Summarizer, Code, etc.) Workflow version number Whether there are unpublished configuration changes ISO timestamp of creation Auto-generated webhook URL for workflow invocations Total number of workflows across all pages Current page number Number of items per page Total number of pages available ## Example Request ```bash theme={"dark"} curl -X GET -H "x-api-key: " \ "https://api.xpander.ai/v1/workflows?page=1&per_page=10" ``` ## Notes * Only workflows (`type: orchestration`) are returned — regular agents are excluded * Results are filtered by API key permissions * Use pagination to handle large result sets * See the [Workflows user guide](/user-guide/build/workflow) for details on the visual canvas and node types # Add Workflow Node Source: https://docs.xpander.ai/api-reference/v1/workflows/nodes/add-workflow-node POST /v1/workflows/{workflow_id}/nodes Add a node to a workflow DAG (action, agent, or advanced) and wire its edges. Cycles are rejected. # List Workflow Nodes Source: https://docs.xpander.ai/api-reference/v1/workflows/nodes/list-workflow-nodes GET /v1/workflows/{workflow_id}/nodes List a workflow's orchestration nodes in a simplified shape. # Remove Workflow Node Source: https://docs.xpander.ai/api-reference/v1/workflows/nodes/remove-workflow-node DELETE /v1/workflows/{workflow_id}/nodes/{node_id} Remove a node from a workflow and scrub edges that pointed to it. # Update Workflow Source: https://docs.xpander.ai/api-reference/v1/workflows/update-workflow PATCH /v1/workflows/{workflow_id} Update an existing workflow's configuration, nodes, or settings Modify a workflow's configuration — update its node graph, instructions, model settings, or notification rules. Only provided fields will be updated. ## Path Parameters Unique identifier of the workflow (UUID) ## Query Parameters Automatically deploy the workflow after updating to apply changes immediately. Without this, changes are staged but not active until a PUT deploy call. ## Request Body All fields are optional. Only provided fields will be updated. Display name Workflow description System instructions for the orchestrator Updated node graph — the full canvas definition with node types, instructions, and connections LLM provider Model version Task-level strategies for retry, stop, and iteration Notification configuration Output format: `text` or `json` JSON schema for structured output Workflow status: `ACTIVE` or `INACTIVE` ## Response Returns the updated `WorkflowResponse` object. ## Example Request ```bash theme={"dark"} curl -X PATCH -H "x-api-key: " \ -H "Content-Type: application/json" \ -d '{"name": "Updated Workflow Name", "description": "New description"}' \ "https://api.xpander.ai/v1/workflows/?deploy=true" ``` ## Notes * Use `deploy=true` to immediately apply changes * Without `deploy=true`, changes are staged and require a separate [Deploy Workflow](/api-reference/v1/workflows/deploy-workflow) call # 2024 Source: https://docs.xpander.ai/changelog/2024/product-updates ## New Features: * **Initial Release:** Official launch of xpander.ai platform. * **LLM Integration:** Support for OpenAI, Claude, and Gemini LLM providers. * **Memory Management:** Basic memory management and tool execution framework (\[SDK Agent Reference]\(/API reference/agents/index)). * **Authentication:** Simple authentication and user management system. ## New Features: * **Ollama Support:** Added support for local model inference via Ollama. * **Agent State Management:** Released beta version of comprehensive state management. ## Improvements: * **Error Handling:** Improved handling for tool executions. * **Documentation:** Enhanced with quick start guides ([docs/01-get-started/01-index.mdx](/overview/what-is-xpander)). ## New Features: * **FriendliAI Integration:** Launched support for FriendliAI with Claude models. * **Dynamic Tool Discovery:** Added mechanism for automatic tool discovery. ## Improvements: * **Performance:** Enhanced performance for high-volume deployments. * **Examples:** Released extended integration pattern examples. ## New Features: * **Streaming Responses:** Added support for streaming from all providers. * **Python Client:** Released new client with simplified API. ## Improvements: * **Tool Compatibility:** Enhanced cross-provider tool format compatibility. * **Memory Consistency:** Improved consistency across multi-turn conversations (\[SDK Agent Reference]\(/API reference/agents/index)). ## New Features: * **LangChain Integration:** Added comprehensive LangChain support. * **Tool Format Conversion:** Released automatic conversion utilities. ## Improvements: * **Memory Initialization:** Enhanced with custom instructions support. ## New Features: * **NVIDIA NIM Support:** Added support for NVIDIA NIM models. * **Persistent Storage:** Enhanced agent memory with storage options. ## Improvements: * **Error Handling:** Improved handling for rate limiting and quotas. * **Examples:** Released multi-step task execution examples. ## New Features: * **Multi-Provider Switching:** Support for switching providers within same session. * **Provider Adapter Pattern:** Released simplified integration pattern. ## Improvements: * **Tool Execution:** Enhanced framework with parallel processing. * **Documentation:** Improved with provider-specific best practices. ## Improvements: * **Message Handling:** Enhanced format handling across providers. * **Tool Extraction:** Improved reliability with explicit provider specification. * **Documentation:** Released extended memory management guides. ## New Features: * **Automatic Format Conversion:** Added message format conversion between providers. * **Python SDK:** Released with expanded provider support. ## Improvements: * **Error Reporting:** Enhanced with provider-specific details. * **Schema Validation:** Improved tool schema validation for better compatibility. ## New Features: * **Alpha Release:** Initial alpha version with basic OpenAI integration. * **Tool Calling:** Support for simple tool calling and execution (\[SDK Tools Reference]\(/API reference/tools/index)). * **Memory Management:** Initial capabilities (\[SDK Agent Reference]\(/API reference/agents/index)). * **Documentation:** Basic documentation and examples ([docs/01-get-started](/guides)). > Note: Current SDK version is v1.47.10 as of this documentation update. # 2025 Source: https://docs.xpander.ai/changelog/2025/product-updates ## New Features: * **Agent planning and enforcement:** Added deep planning capabilities with execution plans, plan updates, enforcement controls, and an ask-for-information flow to gate execution until required details are provided. * **Self-hosted API deployment support:** Enabled running the xpander platform API as a self-hosted container, for increased data privacy. More details here: [https://docs.xpander.ai/api-reference/rest-api](https://docs.xpander.ai/api-reference/rest-api) * **Planning activities in Activity:** The monitoring view in the Agent Workbench now shows a detailed view of the Planning steps that the agent took. ## Improvements: * **Workbench planning configuration:** Added consolidated UI controls for planning, reasoning toolkit toggles, and advanced tool-call configuration, including checklist enforcement. Agent planning and enforcement configuration is available under the Tools tab in the Agent workbench. * **Self-hosted Agent Controller integrations:** Improved support for fetching activity logs and evaluations from remote/self-hosted Agent Controllers, with secure key syncing and cloud fallback. * **Execution plan visualization:** Enhanced chat and activity views to render execution plans and live plan updates with clearer progress indicators. * **Operational reliability:** Improved task/execution synchronization, thread syncing, and queue TTL handling; added automatic agent description generation when missing. * **Model catalog and defaults:** Expanded OpenAI model catalog (including GPT-5.2) and added configurable reasoning effort controls. ## Bug Fixes: * **MCP tooling fixes:** Corrected MCP tool-selection modal behavior and hid unsupported selections for OAuth2. * **Agent execution stability:** Enforced consistent inactive-agent handling. * **Various backend adn UI bug fixes and stability improvements.** ## New Features: * **Agent import/export with knowledge base content:** Agents can now be exported and imported with optional inclusion of associated knowledge bases and document content. This is useful for promoting agents between sandbox and production accounts. Check out the Export/Import calls in the API reference: [https://docs.xpander.ai/api-reference/v1/agents/export-agent](https://docs.xpander.ai/api-reference/v1/agents/export-agent) * **Nano Banana image generation API:** New tool: generate images via your agents with Google Nano Banana. * **Refactored “Create New Connection” flow:** Introduced a new end-to-end UI for creating and editing connections with improved validation and support for multiple auth methods (API key, OAuth2, AWS services with SigV4). * **Expanded OpenAI model catalog:** Added support for OpenAI GPT-5.2 (and additional GPT-5 family variants) in the model selection catalog. * **SalesForce Hosted MCP:** With improvements in MCP and OAuth2 handling, SalesForce Hosted MCP is fully supported and tested. ## Improvements: * **MCP and OAuth2 scope handling:** Enhanced MCP deployment enablement and OAuth scope handling (including additional scopes and refresh-token support). * **Agent activity view refactor:** Improved activity view reliability by migrating legacy sessions into threads on demand and adding a thread evaluation endpoint with caching. * **SDK and A2A tooling UX:** Refined SDK/A2A UI surfaces (e.g., agent card handling, triggers actions, and MCP tool gating) for clarity and consistency. ## Bug Fixes: * **Template and import route stability:** Fixed agent template forward-reference issues and stabilized the template import route behavior. * **UI fixes:** Fixed access scope rendering issues and corrected UI styling/behavior in MCP-related modals and built-in tools. ## New Features: * **Advanced Reasoning Tools:** Added toggles for Advanced Reasoning tools , enabling agents to use think and analyze capabilities for improved planning and decision-making between tool calls. **This feature greatly improves agent performance and it's highly recommended to try it**. Enable the *Advanced Reasoning tools* under the Tools tab in the AI Workbench. * **End-to-end OAuth2 Experience in Remote MCPs:** Use OAuth2 to authorize users against Remote/Hosted MCP Servers via any invocation endpoint. See the feature demo here: [https://xpander.ai/demo-videos/end-to-end-auth-with-mcp-and-oauth2/](https://xpander.ai/demo-videos/end-to-end-auth-with-mcp-and-oauth2/) * **Agentic Memory and Culture Management:** Introduced explicit toggles for agent-managed memory and culture with consolidated settings UI, allowing fine-grained control over agent persistence behavior and memory management. Agentic Culture allows agents to learn from their previous experiences. * **Revamped Agent Activity view:** Now with comprehensive activity tracking with thread-based activity records, exposing task conversations, tool calls, reasoning steps, sub-agent triggers, and authentication events. * **Tool Calls Compression:** Added configurable tool call compression settings to reduce verbose tool outputs and improve token efficiency, with customizable threshold and compression instructions for better context management. * **Reasoning UI Display:** Added visual representation of agent reasoning in the chat UI, displaying Think/Analyze events with title and description for improved transparency into agent decision-making. * **Expanded LLM Provider Support:** * Integrated Google AI Studio (Gemini) with support for various Gemini models. * Added **Helicone** and **OpenRouter** for a much wider selection of models to drive your agents. * Added **Nebius Token Factory** support with aggregated models including Meta Llama, NVIDIA Nemotron, Qwen, DeepSeek, and more. * **Searchable LLM Model Selection:** Enhanced the LLM selection dropdown with search and filtering capabilities to improve usability when choosing from the expanded model catalog. * **Multi-Framework Support:** Enabled support for multiple agent frameworks including Strands Agents, OpenAI Agents, Google ADK, and LangChain. ## Improvements: * **Streaming Performance:** Reduced streaming latency by pre-starting dual streams (SDK and worker) and optimizing Kubernetes metrics collection with non-blocking initialization and shared thread pool executor. * **Framework Settings UI:** Improved framework name and icon display in agent settings for better visual clarity and user experience. * **User Profile Settings:** Enhanced user settings modal with simplified structure and improved rendering behavior. ## Bug Fixes: * **Chat Textarea Responsiveness:** Fixed automatic height adjustment for chat text area in Chat UI, ensuring proper responsiveness across devices including iOS/Safari. * **Failed Task Status:** Properly handle Failed status as terminal state and set finished\_at timestamp to ensure accurate task completion tracking. * **Task Filtering:** Extended task filters with triggering\_agent\_id parameter for improved debugging and task retrieval capabilities. ## New Features: * **AWS Bedrock Integration:** Enabled native AWS Bedrock as LLM provider for agents. * **Helicone Integration:** Added support for Helicone as AI Gateway for LLM providers. ## Improvements: * **Performance Enhancements:** * Reduced streaming latency and improved robustness of agent event pipelines by pre-starting SDK and worker streams and coordinating their outputs. * Optimized Kubernetes metrics collection. * Streamlined execution history updates and improved event-loop responsiveness. * **Configuration and Memory:** * Aligned default user memory settings and improved configuration for agent memory behavior. ## Bug Fixes: * **UI and Configuration Consistency:** * Corrected default user memory behavior to default-off. * **Robustness and Error Handling:** * Improved error handling and graceful shutdown in streaming event pipelines. * Ensured that missing or invalid API keys do not break core agent flows, but only disable related features. ## New Features: * **Generalist Agent Revamp:** Major overhaul of the generalist agent experience, including explicit reasoning tools (think/analyze), task grouping in the WebUI, and a well-known agent card endpoint for client discovery. * **Timezone Awareness:** Chat sessions now capture and sync the user's IANA timezone from the browser to the backend. * **User Details Propagation:** Webhook and agent invocation pipelines now accept and propagate user identity details. ## Improvements: * **UI/UX Enhancements:** * Overhauled the Chainlit WebUI with stabilized task sync indicators, improved task grouping, and live reasoning display. * Refined logs (monitoring) panel with duration indicators, operation icons, and improved readability. * Improved file extraction and rendering for images and attachments in chat threads. * Enhanced connector management in Workbench, including connection switching, multi-delete, and version upgrades. ## Bug Fixes: * **Task Grouping and State Persistence:** Fixed issues with duplicated chat steps, improper task state persistence, and UI artifacts during session reconstruction. * **Silent Agent Task Creation:** Ensured agent task creation is silent in the UI, with accurate progress and completion indicators. * **Connector and Avatar UI:** Resolved connector collapsible section bugs, avatar sizing inconsistencies, and improved tool selection logic. * **Logs Panel and Activity Thread:** Fixed collapse/expand behavior, duration calculations, and error propagation in activity threads. Today's update is relatively short due to the last update being 4 days ago. We're now moving to a weekly update every Sunday. ## New Features: * **OpenAI GPT-5.1 Model Support:** Added GPT-5.1 and additional GPT-5 family variants to the model catalog, with updated context and output token limits for each model. * **Agent Description Field:** Introduced editable agent descriptions in the Workbench and auto-generation of agent descriptions. This will be populated in the Agents list in platform.xpander.ai and chat.xpander.ai (or chat.your-company.com) * **Improved robustness of Task scheduler:** Migrated platform services to async Redis clients and offloaded non-critical work to background tasks for improved throughput and reliability. ## Improvements: * **Environment Management:** Added option to configure default environment for agent deployments. * **Agent Activity Logs UI:** Refined agent activity logs to group user turns, tool calls, and assistant answers for improved readability. * **UI/UX Enhancements:** Improved chat background color handling, loader states for iframe chat initialization, and clarified terminology (e.g., "Executions" to "Tasks"). * **Connector and API Key Management:** Added SQL functions for environment filtering, improved API key selection in OAuth2 flows, and refined connector versioning logic. ## Bug Fixes: * **UI Consistency:** Resolved various UI bugs, including modal race conditions, built-in tool toggling, metrics tab rendering, and chat view background color. * **OAuth2 CLI Flow:** Improved OAuth2 CLI login flow with API key selection, authorization UI, and safe redirect handling. ## New Features: * **OAuth 2.1 Authorization Server:** Introduced a full OAuth 2.1 server with Remote OAuth and Dynamic Client Registration for MCP and API endpoints, including JWT-based authentication and discovery endpoints. Check out the API reference here: [https://docs.xpander.ai/api-reference](https://docs.xpander.ai/api-reference) * **Workbench: Built-in Tools:** Added toggles to enable/disable built-in tools like email sending and sleep toold in the Workbench Tools tab. * **Guardrails and Agno Settings:** Expanded agent guardrails configuration, including PII detection, prompt injection detection, and OpenAI moderation categories. * **Agent Version Naming:** Added support for naming agent versions, with editable version names displayed throughout the UI. ## Improvements: * **Agent Activity Token Metrics:** Exposed input and output LLM token breakdowns in agent activity threads and sessions for improved monitoring and billing. * **Connector Versioning and Upgrade Flow:** Improved connectors table with version selectors, upgrade confirmation dialogs, and better version management. * **UI/UX Enhancements:** Refined metrics counting, improved modal and tab behaviors, clarified terminology (e.g., "Executions" to "Tasks"), and enhanced error handling and session management. ## Bug Fixes: * **Tool-Call Reporting and Error Flow:** Improved reliability of tool-call lifecycle reporting, error event emission, and UI rendering for tool-call steps. * **Thread Activity Metrics:** Corrected token metrics display and layout in thread activity views, ensuring accurate input/output token counts. * **UI Consistency:** Resolved various UI bugs, including modal race conditions, built-in tool toggling, metrics tab rendering. * **Connector and Agent Settings:** Fixed issues with connector version selection, upload modal behavior, and agent settings persistence. ## New Features: * **MCP Connector Management:** Complete UI for creating, managing, and configuring MCP connectors with tool visualization and server selection. * **Environment Configuration:** Enhanced environment settings with sorting, deletion, and configuration management capabilities. ## Improvements: * **Tool Picker Panel:** Redesigned tool selection interface with improved usability and select-all functionality. * **Connector Operations:** Streamlined connector creation and deletion workflows. ## Bug Fixes: * **MCP Server Display:** Fixed MCP server table rendering and connector display issues. * **Environment UI:** Resolved environment skeleton loading and configuration bugs. ## New Features: * **On-Premise Streaming:** Real-time streaming support for on-premise deployments with improved performance. * **Deployed Assets Management:** Comprehensive management interface for deployed assets and configurations. ## Improvements: * **Environment Types:** Enhanced environment type enforcement and validation mechanisms. * **Self-Hosted UI:** Improved self-hosted configuration panels and settings interface. ## Bug Fixes: * **Streaming Text:** Fixed text streaming issues in on-premise environments. * **Environment ID Handling:** Resolved environment ID tracking and validation bugs. ## New Features: * **User Groups:** Enterprise-grade access control with user group creation and management. * **Default Group Assignment:** Automatic group assignment for new users with customizable defaults. * **Granular Permissions:** Fine-grained permission controls at the organizational level. ## Improvements: * **Settings Refactor:** Separated user and admin settings for better organization. * **Onboarding:** Added option to skip onboarding questionnaire for existing users. ## Bug Fixes: * **Group Enforcement:** Fixed user group enforcement and edge function hooks. * **Permission Validation:** Resolved permission validation edge cases. ## New Features: * **Agent Teams:** Multi-agent coordination with coordinate mode for complex workflows. * **Bot-to-Bot Communication:** Direct communication support between agents. * **Sub-Agent Executions:** Hierarchical agent execution with enqueue mechanism. ## Improvements: * **Team Mode UI:** Enhanced team mode interface with coordinate mode toggle. * **Agent Hub:** Improved agent discovery and template selection. ## Bug Fixes: * **Team Sessions:** Fixed session management for team-based workflows. * **Agent Activity Tracking:** Resolved monitoring and tracking issues for team agents. ## New Features: * **Agno 2.0 Integration:** Complete migration to Agno 2.0 framework for enhanced performance. * **Team Mode Sessions:** Advanced session management from Agno for team workflows. ## Improvements: * **Performance:** Significant performance improvements across agent execution. * **Reliability:** Enhanced stability and error handling throughout the platform. ## New Features: * **Connectors v2:** Redesigned connector architecture with improved management capabilities. * **Connector Headers:** Support for custom headers and server\_url configuration. * **Enhanced Tool Picker:** Improved tool selection with better filtering and search. ## Improvements: * **Connected Connector Page:** Redesigned connector details page with better usability. * **Pending Connectors:** Disabled pending connectors to prevent configuration errors. ## Bug Fixes: * **Connector Display:** Fixed connector description and display issues. * **Tool Selection:** Resolved tool picker panel bugs and selection state issues. ## New Features: * **OIDC Parent Accounts:** Support for OIDC parent account authentication. * **Passwordless Login:** Simplified authentication with passwordless options. * **SecretsManager Integration:** Enhanced security with AWS SecretsManager authentication. ## Improvements: * **SSO Configuration:** Improved SSO setup and configuration UI. * **OAuth2 Scopes:** Added readonly scopes for better access control. * **Login UI:** Enhanced authentication interface with better error messaging. ## Bug Fixes: * **User Provisioning:** Fixed user provisioning to assign member role instead of admin by default. * **Login Flow:** Resolved login via URL enforcement and redirect issues. ## New Features: * **Markdown to PDF:** Comprehensive markdown-to-PDF conversion with public static URLs. * **Advanced PDF Styling:** Enhanced styling with improved line spacing, fonts, and table formatting. * **DejaVu Sans Font:** Integrated DejaVu Sans font for better international character support. ## Improvements: * **PDF Table Formatting:** Improved table rendering with proper headers and borders. * **Link Handling:** Better link rendering and word-wrapping in generated PDFs. * **wkhtmltopdf Optimization:** Fine-tuned PDF generation engine for better performance. ## Bug Fixes: * **PDF Generation:** Fixed multiple PDF generation edge cases and formatting issues. * **Character Encoding:** Resolved special character and encoding problems in PDFs. ## New Features: * **Code Interpreter:** Integrated code interpreter for executing code within agents. * **AI Function Generation:** AI-powered custom function generation with expected output prediction. * **Enhanced Function Editor:** Improved function editing experience with better syntax highlighting. ## Improvements: * **Generate with AI Button:** Quick access to AI-powered function generation. * **Function Settings:** Enhanced function configuration options and settings panel. * **Action Routes:** Improved action routing and editor functionality. ## Bug Fixes: * **Function Editor:** Fixed editor state and saving issues. * **Custom Actions:** Resolved custom action execution and configuration bugs. ## New Features: * **GPT-5 Support:** Added support for GPT-5 models with temperature controls. * **Nvidia LLM Provider:** Integration with Nvidia LLM services and Nvidia Nemo. * **Custom LLM Keys:** BYOL (Bring Your Own License) support for custom model keys. ## Improvements: * **LLM Key Management:** Enhanced UI for managing and configuring LLM provider keys. * **Bedrock Provider:** Improved AWS Bedrock integration and error handling. * **Model Selection:** Better model selection interface with provider-specific options. ## Bug Fixes: * **Provider Configuration:** Fixed LLM provider configuration and key validation issues. * **Model Loading:** Resolved model loader and initialization bugs. ## New Features: * **New Pricing UI:** Redesigned pricing interface with transparent tier information. * **Budget Caps:** Set budget limits to control resource usage and costs. * **Builder Seats Management:** Manage team builder seats and permissions. * **Tool Duration Tracking:** Track execution time and resource usage per tool. ## Improvements: * **Resource Monitoring:** Enhanced container usage tracking and cleanup mechanisms. * **Usage Metrics:** Total execution duration metrics and detailed analytics. * **Contact Sales Integration:** Seamless integration with sales team for enterprise pricing. ## Bug Fixes: * **Container Cleanup:** Fixed agent container cleanup for hanged assets. * **Metrics Aggregation:** Resolved metrics collection and aggregation issues. ## New Features: * **Enhanced Webhook Endpoints:** Webhook endpoints with agent\_id in URL paths for better routing. * **Static Webhook Triggers:** Static trigger endpoints with POST method support. * **Webhook Tester Modal:** Agent Webhook Tester with file upload capabilities. ## Improvements: * **Async Webhook Invocation:** Improved webhook handling using xpander-sdk for better performance. * **Form Data Support:** Added application/x-www-form-urlencoded support for webhooks. * **Webhook Output:** Enhanced structured output and response handling. ## Bug Fixes: * **Webhook Configuration:** Fixed webhook modal layout and configuration issues. * **Validation:** Resolved webhook validation and curl generation bugs. ## New Features: * **Complete SDK Refactor:** Major SDK restructure with improved architecture, new agent columns, and enhanced performance. * **Slack Bots Integration:** Comprehensive Slack bot functionality with auto-engage features, conversation starters, and app distributions. * **End Client Authentication:** New authentication system with improved security and performance optimizations. * **AWS Marketplace Integration:** Full integration with AWS Marketplace for seamless deployment and billing. * **Custom Workers & Kubernetes:** Kubernetes cluster support for custom workers with advanced logging and monitoring capabilities. ## Improvements: * **Agent Versioning System:** Complete agent versioning with draft handling and deployment management. * **Webhook System Overhaul:** Organization-level API keys and enhanced webhook functionality. * **Knowledge Base Enhancements:** Advanced CRUD operations, OCR support, and improved document processing. * **Performance Optimizations:** Significant performance improvements across agent workers and API responses. ## Bug Fixes: * **Memory Management:** Fixed memory leaks and improved garbage collection in long-running sessions. * **Authentication Issues:** Resolved various authentication and authorization edge cases. * **UI/UX Improvements:** Fixed multiple interface issues and improved user experience. ## New Features: * **Neon Database Integration:** Multi-tenant database integration with secure vault storage per tenant. * **LinkedIn API Updates:** Comprehensive LinkedIn API controller with expanded endpoint coverage. * **Static File Upload System:** Public CDN upload functionality for static files and assets. * **Image Generation Multi-turn:** Enhanced OpenAI image generation with multi-turn conversation support. ## Improvements: * **Supabase Migration:** Migrated to async Supabase client for improved performance and reliability. * **Chainlit Enhancements:** Better cookie handling, empty state fixes, and conversation starters. * **Agent Builder UI:** Improved agent builder interface with better versioning and status management. ## Bug Fixes: * **Form Submission:** Fixed form handling and submission issues across the platform. * **Agent Status:** Resolved agent status synchronization and draft handling issues. ## New Features: * **CSV File Support:** Added comprehensive CSV file processing and handling capabilities. * **AWS Assume Role Support:** Enhanced AWS integration with assume role functionality for improved security. * **Default API Keys:** Implemented default API key management system for streamlined setup. ## Improvements: * **Slack Bot Performance:** Enhanced auto-engage functionality with rate limiting and improved context handling. * **Agent Performance:** Optimized agent worker implementation for better resource utilization. * **API Security:** Improved authentication parsing and AWS credentials handling. ## Bug Fixes: * **Basic Authentication:** Fixed basic auth parsing issues. * **AWS Credentials:** Resolved AWS credentials configuration problems. * **Thread Management:** Fixed thread mapping and context issues in Slack integrations. ## New Features: * **Mintlify Search Integration:** Added Mintlify search functionality for improved documentation access. * **PR Title Validator:** Implemented automated PR title validation system. * **Agent Import System:** Internal agent import capabilities for streamlined deployment. ## Improvements: * **Agent List Performance:** Optimized agent list handling for organizations with 1000+ agents. * **Error Handling:** Better error handling across various platform components. * **Code Quality:** Enhanced code quality with improved testing and validation frameworks. ## New Features: * **OpenTelemetry Integration:** Comprehensive observability and monitoring with OpenTelemetry. * **Custom Deployment Versioning:** Support for deploying specific versions with custom configurations. * **Preflight Testing:** Build preflight checks to ensure deployment reliability. ## Improvements: * **Resource Allocation:** Optimized Kubernetes resource allocation and pod lifecycle management. * **Build System:** Enhanced build system with better dependency management. * **Deployment Pipeline:** Improved deployment pipeline with better error handling and rollback capabilities. ## New Features: * **Enhanced Webhook System:** Improved multi-file upload support with better handling of large batch files for document processing agents. * **Secure File Access:** Added presigned URLs for file access with 30-day validity period. ## Improvements: * **Documentation Updates:** Enhanced documentation with clear examples for file processing workflows. * **Performance Optimization:** Optimized large batch file handling for improved agent performance. Read more here: [https://docs.xpander.ai/guides/task-sources/webhooks](https://docs.xpander.ai/guides/task-sources/webhooks) ## New Features: * **Model Context Protocol (MCP) Support:** Added native support for MCP across all agentic interfaces. * **Cross-Provider Compatibility:** Enhanced compatibility with standardized MCP implementations. ## Improvements: * **Agent Performance:** Improved agent performance with optimized MCP message handling. ## New Features: * **Extended LLM Provider Support:** Added support for latest model versions across multiple providers. ## Improvements: * **Response Latency:** Improved response latency for high-volume agent deployments. ## Bug Fixes: * **Memory Management:** Fixed memory management issues in long-running sessions. ## New Features: * **Agent-to-Agent Communication:** Added support for direct communication between agents. * **Cross-Provider Compatibility:** Updated message format compatibility across providers. ## Improvements: * **Error Handling:** Enhanced error handling for network timeouts during tool execution. ## Bug Fixes: * **UI Rendering:** Fixed rendering issues in the agent configuration panel. ## New Features: * **Agent Template Gallery:** Released template gallery for faster development workflows. * **Environment Variables:** Added configuration support for environment variables. ## Improvements: * **Memory Efficiency:** Improved memory efficiency for large context windows. * **Schema Validation:** Enhanced validation for custom tool schemas. ## New Features: * **Claude Model Support:** Added support for latest Claude models. * **Python SDK Examples:** Released new enterprise use case examples. ## Improvements: * **Tool Execution:** Improved performance with parallel processing capabilities. ## Bug Fixes: * **Tool Extraction:** Fixed issues with certain response formats. ## New Features: * **Unit Testing Framework:** Added framework for agent behavior validation. * **Performance Monitoring:** Released dashboard for agent performance tracking. ## Improvements: * **Tool Coordination:** Enhanced execution coordination between multiple agents. * **Documentation:** Improved guides for custom tool development. ## New Features: * **Mixtral Model Support:** Added support for additional Mixtral models. * **Structured Logging:** Implemented enhanced logging with structured output. ## Improvements: * **Cross-Provider Compatibility:** Enhanced compatibility for tool formats. ## Bug Fixes: * **Serialization:** Fixed issues with nested tool responses. ## New Features: * **Debugging Tools:** Released comprehensive debugging tools for agent development. * **File Attachment API:** Added support for file attachments via API. ## Bug Fixes: * **Memory Initialization:** Fixed issues with provider switching scenarios. ## New Features: * **Agent Metrics Dashboard:** Released comprehensive metrics and analytics dashboard. * **Runtime Tool Registration:** Added capabilities for dynamic tool registration. ## Improvements: * **Error Reporting:** Enhanced reporting with context preservation. * **Message Handling:** Improved format handling for all providers. ## New Features: * **OpenAI Model Support:** Added support for latest OpenAI models. * **Python Decorators:** Released decorator-based tool registration system. ## Improvements: * **Authentication:** Enhanced with automatic token refresh capabilities. ## Bug Fixes: * **Tool Execution:** Fixed timeout handling issues. ## New Features: * **Memory Management:** Enhanced system with retention controls and user-specific isolation. * **Multi-User Support:** Improved state management for multi-user scenarios. ## Improvements: * **Documentation:** Released guides for edge deployment scenarios. ## New Features: * **Multimodal Capabilities:** Added support for multimodal agent interactions. * **Document Processing:** Released comprehensive examples and templates. ## Improvements: * **Security:** Enhanced handling of sensitive data. * **Telemetry:** Improved agent execution monitoring and analytics. # Product Updates Source: https://docs.xpander.ai/changelog/product-updates ## New Features: * **Custom connector builder in the new UI:** A new connector generator UI creates a custom connector from any OpenAPI spec, with AI enrichment when available and a spec-only path when it is not. Connector creation runs in the background so closing the dialog mid-run is safe, and connectors now have a full lifecycle: upload a new spec version (preloading the current auth method), delete, and versioned generator updates with an ownership guard. * **One Providers table for LLM settings:** LLM settings now show a single Providers table with keys, models, and costs per provider. Built-in rows meter the default rate while BYOL rows own their model costs, platform-wired default providers show their real Ready state, and provider costs are editable on licensed installs. A new usage and charges card shows BYOK cost in dollars, and wallet usage reads expose per-bucket pricing sources. * **Workflow run history and replay:** Workflows now record full run history with per-node runs, node history, and replay; a run test opens the task-run card, and the execution log gained an orchestration mode. ## Improvements: * **Faster first token on long threads:** Gateway first-token latency was cut significantly on long conversations. * **Sidebar polish:** Building on the new Conversations list, rows gained an action strip with double-click rename, phone swipe gestures, visible channel threads, and a failed run's red count now clears once you look at the agent. * **Slack:** Auto-engagement now works for agents at any sharing level, and attempting to connect a Slack workspace already held by another organization returns an actionable explanation instead of a generic error. * **Scheduled runs pace themselves better:** Daily managed schedules are spread across the whole day instead of clustering on the hour, and scheduled agent jobs are jittered to avoid thundering herds. ## Bug Fixes: * Fixed steered messages rendering twice in the chat thread, and a user message being duplicated after a custom-agent task completed. * Fixed message text disappearing when a mention pill was rendered, and the MCP tool picker losing its options across a refresh. * Fixed Google Drive/Gmail built-in tools returning 500 on certain calls, and a Google Analytics report call failing with a 404. * Fixed Live Surfaces not being accessible in shared conversations on self-hosted installs, and crash-recovered turns now surface their real result over MCP. * Fixed zero-progress task stalls when a local MCP server was starting up, and workspace MCP servers now launch by resolved path and explain failures from both output streams. * Fixed workflow run steps and workflow tool rows showing raw internal ids instead of readable names. * Fixed attachment upload failures into the workspace passing silently — they now surface with a toast. * Fixed a legacy reasoning card reappearing at the start of some runs. * **As always, our agents and humans continuously fix various bugs, and sometimes create new ones (that will be fixed in the next update.)** ## Improvements * **Find agent work from the sidebar:** The Conversations list brings agent, person, source, date, and status filters together, with pinned conversations, upcoming scheduled runs, and a See all view. See [Tasks](/guides/omni/building-agents/tasks). * **Builder chat:** Intermediate builder narration is suppressed while a build is in progress; normal conversation responses remain available outside the build. ## New Features: * **Shared Sessions:** Put several people and several agents in one conversation. Turn an existing conversation into a shared session, choose who and which agents join, chain agents inside the room, and let an auto-engage judge decide when the agents should answer instead of staying silent. Sessions carry their own permissions, presence, run controls, notifications, and a sessions finder, plus a session file workspace with versions, signed downloads, composer attachments, and copy/listen actions on messages. * **Visual Workflow Builder in the new app:** The workflow automation builder was migrated to the new User Interface. It allows you to build deterministic workflows for specific use-cases, while having an agentic base running the workflow. The meaning is workflows that are much easier to build, because you don't have to map specific fields between nodes and steps. The Workflows are extremely robust and allow scheduling and Slack triggers, public webhook triggers, a condition wizard, parallel/pointer/group/end nodes, a wait node that pauses for human approval by email or webhook, per-node model and tool selection through the skill picker, a code node that can generate with AI, per-node diff review, and a pending-changes bar with an explicit publish step. * **MCP Registry refreshed:** An organization-wide registry for MCP servers, with its own settings tab, one canonical server identity, name-aware deduplication and a conflict dialog, per-row health dot, DCR badge and connection check, token-holder and usage dialogs, and a management API covering write policy, usage, probes, tokens, and discovery. Inline MCP servers can be added to the org registry straight from the add form, and deleting an entry says exactly which agents lose the server. * **Gated commands:** Mark specific commands as gated so an agent holds them and notifies a named human for approval instead of failing quietly, with an editor for per-gate approvers and notification channels bound to real organization members. * **Workspace database viewer and editor:** Open a `.db` file in an agent's workspace as a real database — browse tables, click a cell to edit it, and save what you typed. This feature goes along with enabling the "Local database" skill that can be enabled for any agent under the "Core skills" section - effectively giving every agent a local database running in its worksapce, and now also available for visual browsing and queries right in the UI. * **Pin the model a scheduled run uses:** A scheduled task can now pin its own model instead of always inheriting the agent's default. * **Skill bundles:** Download a skill's bundle, and rename a skill from its row menu. ## Improvements: * **Connector setup is easier to get right:** A new ApiKey auth type, a URL placeholder and example derived from the connector's own spec, and a collapsed "Setup guide" that renders markdown with working links. Custom connector creation is now gated on the platform license rather than the retired billing check. * **MCP sign-in and callbacks:** The MCP redirect URL is now a generic, organization-independent callback (previously registered URLs keep working), DCR verdicts are persisted with probe health, and a refused sign-in explains itself instead of showing a raw HTTP blob. This makes it easy to connect to Remote MCPs with whitelisted callback URLs. * **Local MCP servers:** The form says which commands are supported and lints what you typed, the server is actually tested in the agent's workspace at save time, a held test is polled instead of timing out, and a chatty server's own words survive instead of being drowned in per-line tracebacks. * **Agent export and import fidelity:** Exported agents carry their tools, custom functions become tools, archives upload (and say so when they cannot), imported skills attach and publish to the registry, MCP auth and connector authorization links are generated for the importer, and a strict parity contract with a failure report replaces silent gaps. * **Quieter, clearer chat:** Mid-build builder prose and in-chat plan drawing were removed, toasts are centered, the agent's send-email built-in prefers a connected mailbox, and small text PDFs are answered on the gateway without spinning up a sub-task. ## Bug Fixes: * Fixed a failed activity read being able to kill a live workspace, and an activity timestamp being read in the wrong shape. * Fixed a batched heartbeat deadlocking during a rollout, and agent-derived caches surviving a change to the agent. * Fixed duplicating an agent not copying its workspace, and catalog specs being restored from a stale cache by a racing write. * Fixed a manifest mistake leaving a half-done task instead of something repairable, and a dynamic-prompt test not being able to call an operation just attached to the agent. * Fixed a cold workspace probe being reported as "Did not start", agent creation failing quietly, and an organization switch failing without saying why. * Fixed a cluster of dead clicks on controls that could not act, missing thumbs up/down and Share on agent messages, a keynote overlay eating clicks while it faded out, and the sidebar reading "2M AGO" for two minutes ago. * Fixed the Slack workspace staying connected after the app was removed on the Slack side. * **As always, our agents and humans continuously fix various bugs, and sometimes create new ones (that will be fixed in the next update.)** ## New Features: * **External Vaults (Azure Key Vault):** Attach your own Azure Key Vault to xpander, browse and import its secret names, and let agents resolve the real values live at use time. * **Agent credential bindings:** A new Credentials panel lets you bind vault secrets to a specific agent, choose how each credential is used, and require human approval on an individual binding. * **Human approval for individual tool calls:** Hold a specific tool call for approval, with rules that can be scoped to named tools and set from an MCP server's row, enforcement on MCP tools, a named approver who is actually notified, and a link the approver can act on. * **Agent import & export contract:** Export an agent to an MCP client such as Claude Code and import a Claude agent back into xpander, with a manifest engine, MCP consent, approvals over MCP, a secure workspace-secrets handoff page, and a conformance suite behind it. * **Local MCP servers on any agent:** Local (stdio) MCP servers now run inside the agent's own workspace, so any agent can register one from the chat wizard or the skills form, edit its environment after attaching, and keep it claimed across restarts. * **Self-scheduling agents in the conversation:** Omni can book its own follow-up runs, an agent's own scheduled runs appear in the conversation, xpander-managed default schedules and an autonomous heartbeat pace themselves, and the schedule dialog has Simple/Advanced modes that generate a cron and prompt from free text. * **Model access control:** Organization and group model allowlists are enforced on save and at run time, model pickers show only the allowed set, and BYOK-only providers are gated when no key is available. * **Workspace secrets over the API:** A new API-key endpoint sets an agent's workspace secrets programmatically — no browser and no model in the loop. * **Live Surface component capture:** Live Surface blocks now have stable ids and an isolated render route, so a single block can be captured as an image and reused elsewhere. ## Improvements: * **Agents know their own context:** An agent is now aware of its email address, its organization id, and its channel presence (WhatsApp number, Slack/Teams channels, MCP endpoint, app names), and every message carries its own timestamp instead of requiring a clock tool. * **Slack polish:** A tables toggle, link unfurls, single-call block screenshots, structured JSON replies rendered human-readable, thread replies that carry the agent's identity, self-scheduled output routed back to the originating Slack thread, and DMs that honor the assistant's New Conversation button. * **Approvals read like decisions:** The approvals table and panel gained per-class tabs, a searchable multi-select people filter, one save across classes, honest phrasing instead of operation ids, and notifications that open exactly the request they are about. * **A stale tab tells you:** When a new UI build ships, open tabs get a friendly reload prompt instead of silently running an old version. ## Bug Fixes: * Fixed a secret change bouncing the workspace and returning 503 for in-flight tool calls. * Fixed a client disconnect being able to kill a running gateway turn, and failed tool calls not reaching the activity trace. * Fixed the tool-call summary racing the tool result and caching "No data returned". * Fixed agent-sent messages duplicating the platform's own channel reply. * Fixed the theme defaulting to dark on a fresh device in the legacy app, a duplicated `#` in the Slack channel picker, and the agent owner chip showing the viewer instead of the owner. * Fixed shared workspace media not rendering on async task results, and the builder asserting a review card that never rendered. * **As always, our agents and humans continuously fix various bugs, and sometimes create new ones (that will be fixed in the next update.)** ## New Features: * **Skills Registry:** Create, edit, share, and import reusable skills from a shared org-wide library. Skills can be private, shared with a group, or org-wide, install in one click, and show provenance badges (platform, organization, or private). Skills can also be exported into the registry directly from MCP clients like Claude. * **Channels settings pane:** Omni discovery, Email, Slack/Teams, and developer/API access for an agent now live in one consolidated Channels panel instead of scattered across Advanced settings and separate dialogs, including inline per-channel configuration and output-format instructions for Slack replies. * **SSO group sync:** Link xpander user groups to identity-provider groups (Okta, Entra) with a configurable group claim and extra scopes, so group membership can sync from your SSO provider. * **Cloud runtime toggle:** Organizations with a self-hosted environment can turn off the xpander-cloud agent runtime entirely, hiding cloud agents from non-staff users. * **New Live Surface chart:** A grouped-horizontal-bars block is now available for building comparison charts in Live Surfaces. * **Reveal-on-demand API keys:** View or copy the full value of an API key on demand (for the key's owner or org admins) instead of only at creation time; keys otherwise display as a masked prefix/suffix. ## Improvements: * **Delegated task visibility:** The Task Manager now shows the steps and final result of work an agent delegated to another agent, instead of just the dispatch acknowledgment. * **Buy-credits dialog:** Now shows free bonus credits as a clear tag and the effective cost per credit for each pack. * **Slack/Omni engagement discipline:** Omni now only answers in shared channels when explicitly mentioned, uses stricter judgment on ambiguous thread replies, and clearly attributes background images carried from earlier channel messages so it doesn't confuse them with the current request. * **Model picker clarity:** Models that share the same display name (e.g. two Claude Opus variants) now show a distinguishing qualifier so they're no longer indistinguishable in the picker. * App fonts switched to SF Pro and SF Mono on Apple devices for a more native look. ## Bug Fixes: * Fixed the Live Surface toggle sometimes closing an open surface instead of opening the surfaces list. * Fixed Live Surface data-table rows inviting a click that did nothing when the row had no associated link. * Fixed duplicating an agent showing a generic "could not duplicate" error instead of the actual reason. * Fixed a harmless console error thrown when stopping a voice note recording. * Fixed the onboarding keynote's final screen not responding to a click the way earlier screens did. * Fixed Slack and Microsoft Teams channel history and message-read reliability issues. * **As always, our agents and humans continuously fix various bugs, and sometimes create new ones (that will be fixed in the next update.)** ## New Features: * **Agents in Slack, Whatsapp and Telegram:** Describe what you need and Omni can build a new agent there, connect required accounts through secure links, and communicate to agents through these new channels. * **Mid-run steering:** Send corrections while an agent is working and apply them at the next step, or interrupt and re-run with a new message. * **Notifications across tasks and conversations:** Subscribe to individual tasks or entire conversations, manage alerts from the new Notification Center, and receive supported notifications through browser notifications, email, or WhatsApp. * **Custom actions and dynamic system prompts:** Build and test custom code with presets, connector-generated examples, sandbox execution, AI-assisted generation, and workspace secrets. Agents can also run custom code at prompt time and append the result to their context. * **MCP setup and richer MCP apps:** Register, test, and enable MCP servers from chat, connect MCP clients through an OAuth consent screen, and render agent cards inline in supported clients like Claude and ChatGPT. * **Review and publish agent changes from chat:** Agent edits proposed in conversation can be staged, reviewed, published, discarded, or rolled back before they affect the live agent. * **Richer agent outputs:** Completed background tasks can render directly in chat, while Live Surfaces now support interactive maps and filterable run traces. * **Public workflow webhooks:** Workflow webhook triggers can expose a public invocation URL that does not require an API key. ## Improvements: * **Better mobile chat:** Reworked navigation, composer behavior, keyboard handling, touch interactions, and scrolling to make the web experience work better on mobile. * **Richer model picker:** Model details now include description, context window, capabilities, and credit pricing, with models shown in the platform's catalog order. * **Better sharing and invites:** Shared links are copied automatically, recipients are notified, and invite flows now provide clearer member status, resend controls, and per-recipient results. * **Improved web search results:** Search results now render as ranked sources with favicons and snippets instead of a generic data table. * **Refreshed platform emails:** Transactional emails now use the updated xpander design. ## Bug Fixes: * Fixed connector authorization links sent during chat-based agent builds sometimes failing after an authentication redirect. * Fixed task rows briefly showing incorrect running or completed states and delays when opening task details. * Fixed duplicate notifications being sent for repeated runs of the same scheduled task. * Fixed stale sign-in prompts and related sign-in redirect loops in embedded chat. * Fixed the model picker not scrolling to the currently selected model. * **As always, our agents and humans continuously fix various bugs, and sometimes create new ones (that will be fixed in the next update.)** ## New Features: * **Agent glyph identities:** Every agent now gets a generated glyph identity (gradient tile + icon) instead of a generic robot avatar or emoji, with a hue slider and searchable icon picker to customize it. * **Custom action editor:** The custom-code editor gained a full authoring experience: ready-made presets (HTTP calls, CSV parsing, S3, PostgreSQL, current-user lookups), a connector browser that generates working code for any attached operation, a "Run test" button that executes code in a real sandbox against a seeded test event, and an AI "Generate" button that writes code using your workspace's secret names. * **Live Surfaces map block:** Agents can now publish interactive maps in Live Surfaces, with street-level tiles, zoom/pan, markers, notes, and routes, tuned for both desktop and mobile. * **Live Surfaces run-trace block:** Agents can publish a step-by-step trace of a debugging run as a Live Surface block, with filterable steps instead of a raw tool-call log. * **One widget per turn:** Builder tool cards (debug, eval, build, comparison, skills) now fold into a single turn-scoped task card instead of stacking multiple separate widgets in the same reply. * **MCP registration wizard in chat:** Register, test, and enable a new MCP server without leaving the conversation, with honest connection health and error reporting. * **Draft, review, publish, and roll back agent changes from chat:** Agent edits proposed in conversation go through an explicit publish/discard step with a pre-publish readiness check, so changes are staged and reviewable before they go live. * **Dynamic system prompts:** Agents can run custom code at prompt time and append its output to their context, with a dedicated editor, presets, and pre-save validation of secret references. * **Mobile web support:** The chat composer, keyboard handling, and touch interactions were reworked to make mobile web a fully supported surface. * **Cmd+K command palette:** Jump to any agent with fuzzy search, or paste a thread/task id to jump straight to its conversation. * **New platform email templates:** Every transactional email sent by the platform now uses the refreshed xpander design. ## Improvements: * **Chat scrolling and rendering:** The chat pane now pins to the bottom based on user intent rather than fighting the stream, eliminating render/scroll loops and duplicate answer rendering for sub-agent tasks. * **Mention picker:** @mentions can now be typed anywhere in a message (not just at the end) and correctly match agent names containing spaces. * **Sidebar navigation:** Each conversation row now shows a type glyph, with a filter to switch between conversations and tasks; the running-status indicator is a clearer solid dot with a halo. * **Model catalog:** Claude Opus 5 support was extended with correct Bedrock temperature handling and a larger context window with caching. ## Bug Fixes: * **Favorites cards:** Fixed agent names collapsing to zero width and content spilling outside the card border on the Favorites strip. * **Gateway responses:** Fixed cases where a gateway sub-task's raw JSON envelope leaked into the chat UI instead of being rendered as its final result. * **As always, our agents and humans continuously fix various bugs, and sometimes create new ones (that will be fixed in the next update.)** # New Product launch! **Introducing Omni:** Omni is your AI forward-deployed engineer: the place where you describe a business outcome and get back a working, agent-powered application. Instead of assembling an agent piece by piece, you tell Omni what you want your team to be able to do. Omni asks the clarifying questions it needs, designs the frontend experience, creates and configures the backend agent, connects the models, skills, tools, and data it needs, and reports back when the application is ready. Ask it "can you build me a Redshift Analyzer?" and it builds the whole thing. Two things make Omni different from a chat window. It brings its own computer: every agent gets a real cloud workspace with files, a browser, and a terminal, so it does the work rather than describing it. And it answers visually: instead of a wall of text, you get a Live Surface your team can open, share, and act on. **Agentic Applications:** The thing Omni builds. An Agentic Application pairs a backend agent (model, skills, tools, system prompt, data access) with a live frontend your team actually uses: chat to ask and iterate, Live Surfaces showing current state, reports, dashboards, and approval flows. Chat is useful for asking. Agentic Applications are useful for working. **A new app:** Omni lives in a ground-up rebuild of the xpander web experience at chat.xpander.ai. It is chat-first and canvas-based: conversations on the left, and a deck of cards on the right where tasks, Live Surfaces, agent settings, and workspace files open beside the conversation. The platform at platform.xpander.ai remains the control plane for governing everything you build. #### Try it now: [https://chat.xpander.ai](https://chat.xpander.ai) ## What's new: * **Omni, your AI forward-deployed engineer:** Every user gets a personal Omni agent. It finds the right agent for a job, delegates work to it, or does the work itself. It remembers you across conversations, and it can invite a teammate or ask you for a credential without leaving the chat. * **Build an agent by describing it:** Omni creates, configures, deploys, and schedules other agents from inside the conversation. A single evolving build card walks you through it, discovers your organization's real connectors and models, collects every account it needs behind one approval step, and lets you refine with "not quite right?" before the agent goes live. * **Live Surfaces:** Pin a file the agent generates and it becomes a living view your team can open at any time: a dashboard, a brief, an approval board, a status tracker. The agent keeps regenerating it on a schedule, on a webhook, or on demand. Surfaces render charts, tables, and interactive checkboxes, work in right-to-left languages, open full screen, and each one has a constant shareable link. You can ask the agent questions about a surface, or trigger it from one. * **Agent computer:** Each agent gets its own cloud workspace with files, a browser, and a terminal. Drag and drop a folder in, search and sort it, preview JSONL, PDF, and Markdown, and edit code in place. * **Materially faster:** A sustained push on time to first token, plus agent workspaces that prewarm on first interaction, cutting cold starts and creating a best-of-breed agentic experience. * **Share your work three ways:** Publish a single Live Surface as a public link, share a read-only conversation that teammates can branch and reply in, or publish the whole agent as a branded application with view, use, or edit access. Grant access to individual people, to user groups, to your whole organization, or to anyone with the link, and restrict an organizational Live Surface to just the groups that should see it. * **Steer work while it runs:** Queue messages while the agent is working, stop a run, or steer a task mid-flight with a free-text nudge instead of killing it and starting over. * **Interactive cards in the conversation:** The agent asks clarifying questions, suggests tools and connectors, requests a secret through a secure card whose value never appears in the chat, or invites a teammate, and you answer inline. * **Task Manager:** One place to see every run across every agent, follow live progress, drill into a task, and stop something that is still going. Filter by agent, by who started it, or by where it came from (chat, Slack, webhook, or a schedule), and walk back through a timeline grouped by today, yesterday, last week, and older. * **Choose how the agent works on each message:** A mode picker in the composer sets the shape of the next reply. Instant for fast answers to direct questions, Auto to balance speed and depth, or Deep work to delegate long work and get a document back. The mode sticks to the conversation until you change it. * **Finished tasks become documents:** A completed task is no longer a status strip. It renders as a card with a title, the connectors it touched, an excerpt you can expand, any Live Surface it produced, and a footer with status, time, steps, and cost. * **Jump between runs from the top bar:** A Home / Agent / Thread breadcrumb sits in the navigation bar, and the last segment is a switcher across every run of that agent, including typed threads, inbound emails, scheduled work, and webhook triggers, with search and hover preview. * **Skills:** Give an agent a capability by wrapping a tool, an API, a connector operation, an MCP server, a custom action, a knowledge base, or another agent. Generate a new skill from a plain-English description, test it, and attach it. * **Triggers and schedules:** Give an agent its own email address, put it on a cron, or fire it from a webhook. Agents can also schedule their own follow-up work. * **A sidebar that keeps up:** Conversations sorted by last activity and grouped by day, live status dots on running work, inline rename, and quick-switch shortcuts for your pinned agents. * **Talk to your agents from your own code:** A public API drives the same multi-turn conversational loop the app uses, including message queueing, steering, and sub-task dispatch. Check the API reference at [https://docs.xpander.ai/api-reference](https://docs.xpander.ai/api-reference) * **Rich answers:** Mermaid diagrams, Vega-Lite charts, KaTeX math, syntax-highlighted code, and large CSVs render inline. Voice works in both directions, with dictation in and speech playback out. * **Enterprise controls:** Budgets per task, agent, user, and sub-organization with threshold alerts to email, Slack, or webhook. Plus audit logging with export, user groups, OIDC single sign-on, custom logo and accent color, and self-hosted environments that fall back to the xpander.ai cloud relay when your private environment is unreachable. * **Expanded model catalog:** As always, the xpander platform allows you to work with a huge model provider catalog. ## New Features: * **Stop task API:** A new public API endpoint (`POST /v1/tasks/{task_id}/stop`) allows callers to signal a running agent task to stop cleanly across environments. The stop signal is propagated to the agent worker so in-flight tasks can terminate gracefully. * **Per-execution LLM overrides:** Agent runs can now specify `llm_model_provider`, `llm_model_name`, and `llm_reasoning_effort` at invocation time, overriding the agent's default model settings for that execution only. * **Custom connector OAuth2 support:** Custom connectors now support OAuth2 client credentials flows — credentials are stored securely in the vault and appended to token requests automatically. * **Expanded Amazon Bedrock model catalog:** Added 47 new Amazon Bedrock models from 11 vendors (including Mistral, Writer, Luma, Stability AI, and others). Models are immediately available in the LLM provider selection across agents, workflows, and nodes. * **"Only running" filter for Agent Monitor:** A new filter in the Agent Monitor's thread list shows only actively running threads, making it faster to spot and inspect tasks that are currently executing. * **Redesigned Metrics page with cost tracking:** The Agent Metrics page has been fully redesigned with per-model and per-agent LLM cost charts (USD), an execution count breakdown ## Improvements: * **Remove agent from folder:** Agents can now be removed from a folder via the Actions menu without deleting the agent itself. * **Improved agent defaults:** New agents are created with `deep_planning` enabled, `num_history_runs` set to 50, and `reasoning_tools_enabled` turned on by default, giving agents better out-of-the-box planning and context recall. * **SSE keepalive pings:** The server-sent events (SSE) stream now sends a keepalive comment every 15 seconds, preventing proxies and load balancers from closing idle connections during long-running tasks. ## Bug Fixes: * **Chat spinner stuck after task completes:** Fixed a regression where the hosted chat loading spinner remained visible after a `TaskFinished` event was received, leaving the UI in a perpetual loading state. * **As always, our agents and humans continuously fix various bugs, and sometimes create new ones (that will be fixed in the next update.)** ## New Features: * **OAuth2 JWT authentication for the API:** The public API now accepts OAuth2 JWTs (via `Authorization: Bearer`) alongside existing API keys. * **Task duration and live running status on thread cards:** Agent Monitor thread cards now display the total wall-clock duration of each task and a live pulsing indicator for tasks that are still running. Duration and status stay synchronized between the thread card and the logs side pane. * **Slack bot: configurable channel history on new threads:** A new per-bot setting controls whether the agent receives recent channel conversation history when @mentioned to start a new thread. The toggle is available in the Slack agent Settings tab and defaults to the previous behavior (history included). * **Friendly tool names in activity log and chat:** Built-in xpander tool slugs now display as short, human-readable labels (e.g. "Write file" instead of `xpworkspace-file-write`) in the activity log and hosted chat UI. ## Improvements: * **Faster agent workspace cold starts:** Workspace pods now resolve the sandbox image to an immutable digest reference, allowing Kubernetes to skip image pulls when the image is already cached. * **Agentic task scheduler reliability:** The task scheduler UI now keeps interval, hour offset, and day-of-week controls in sync with the underlying cron expression. ## Bug Fixes: * **Protected agents and workflows cannot be deleted:** Agents and workflows flagged as non-deletable are now protected at both the API (returns 403) and UI (delete controls are hidden, bulk delete skips protected items with a notification). * **Monitor tab edit controls no longer visible:** The Edit button and version history dropdown are now hidden when the Monitor/Activity tab is active in the agent builder. * **Amazon Bedrock model provider stability:** Fixed a startup crash in agent-worker pods caused by AWS SDK version drift during upgrades. * **As always, our agents and humans continuously fix various bugs, and sometimes create new ones (that will be fixed in the next update.)** ## New Features: * **Slack Human-in-the-Loop (HITL) approvals and notifications:** Slack integration now supports approval flows and notification threading, including per-thread LLM cost display directly in Slack messages. * **LLM cost visibility:** Per-thread and per-task LLM cost (USD) is now exposed via the public API and displayed in agent monitoring thread card. * **Workspace context retrieval tool:** A new built-in agent tool allows agents to retrieve large or context-optimized workspace files with guardrails to prevent oversized context injection. * **Live Slack thread event rendering:** Agent task stream events are now live-rendered in Slack threads as the task progresses. * **Custom connector OpenAPI version upload:** Connector owners can now upload a new OpenAPI spec version for their custom connectors directly from the UI. * **xpander hosted MCP improvements:** Enhanced xpander MCP for more reliable agent construction and registration. ## Improvements: * **Workflow layout:** Workflow canvas layout now uses subtree-aware positioning, reducing node overlap and improving readability for complex graphs. ## Bug Fixes: * **404 responses for missing agents/workflows:** The public API now returns proper 404 responses when an agent or workflow cannot be found. * **As always, our agents and humans continuously fix various bugs, and sometimes create new ones (that will be fixed in the next update.)** ## New Features: * **Agent Self-Scheduling:** Agents can now schedule one-shot future runs of themselves. Agents fetch their current task ID and create a scheduled follow-up run at a specific future time — no external cron wiring needed. Self-scheduling can be enabled or disabled per-agent from the Tools tab * **Workflow Schedule Node:** Added a new "Schedule" node type for workflows that pauses execution and resumes at a chosen target node at a future time. Schedule expressions are written in natural language (e.g. "in 1 hour", "next Monday 9am"). * **New LLM models — Claude Opus 4.7 and GPT-5.5:** Added Claude Opus 4.7 (available via Anthropic and Amazon Bedrock) and GPT-5.5 to the available model catalog across agents, workflows, and workflow nodes. ## Improvements: * **Tasks page: execution location column:** Added a Location column to the Tasks page showing which environment each execution ran in - xpander cloud, or the name of the self-hosted location. ## Bug Fixes: * **As always, our agents and humans continuously fix various bugs, and sometimes create new ones (that will be fixed in the next update.)** # New major feature! * **Agent Workspace:** Added dedicated workspace environments per-agent with persistent shell, file editing, code search, and file sharing tools so agents can safely work with larger outputs and generated artifacts. ## New Features: * **Three-layer context optimization for long-running agent sessions:** Introduced layered context optimization, including large output offloading, retry-aware compaction, and manual context compaction flows to keep agents reliable under heavy context pressure. * **Slack workflow formatting controls:** Added workflow-level Slack formatting instructions so teams can define how structured workflow outputs should be rendered in Slack. * **New model provider support:** Added support for Tzafon LightCone and ByteDance ModelArk providers across the platform. * **Secure static HTML sharing:** Shareable HTML reports can be created via built-in agent tooling. ## Improvements: * **AI-native Microsoft Outlook connector:** Added Outlook support for mail, calendar, contacts, and attachments with secure URL-based attachment handling and optional text extraction. * **Task history filtering:** Added date range filters for task history APIs so teams can query execution history within a specific time window. * **Agent and workflow creation experience:** Simplified agent creation with sensible defaults for regular and personal agents, improved tool selection with grouped operations and bulk selection, and reset creation modals more reliably when closing and reopening them. * **Agent activity and compaction visibility:** Improved the activity timeline to clearly show context optimization starts, results, and failures, with better titles and detailed payload views. * **UI clarity across agents and connectors:** Improved agent feature descriptions, simplified deprecated planning and memory settings, and made connector logo selection more consistent. ## Bug Fixes: * **External request forwarding:** Fixed request forwarding so empty query parameters are stripped before calling external APIs, reducing downstream errors. * **Agent asset cleanup:** Fixed deletion flows for container-based agents so associated agent assets are purged when the agent is removed. * **As always, our agents and humans continuously fix various bugs, and sometimes create new ones (that will be fixed in the next update.)** ## New Features: * **Agents can now use workflows as tools:** Added workflow selection in the builder and execution support so agents can invoke workflows as part of larger orchestrations. * **Structured SOUL configuration for OpenClaw agents:** Added a dedicated SOUL editor in the workbench and structured SOUL.md generation for agent containers, making agent identity and behavior easier to define and maintain. * **Expanded AWS connector capabilities:** Added richer Amazon EKS troubleshooting tools and improved Redshift discovery, schema inspection, sampling, and connection flows. See connector docs here: [https://docs.xpander.ai/connectors](https://docs.xpander.ai/connectors) ## Improvements: * **Atlassian cloud site selection for connectors:** Added cloud selection for Jira, Jira Sprints, and Confluence connectors so users can explicitly choose the target Atlassian site during setup. * **Hosted assistants and activity views:** Improved thread loading, sub-task activity rendering, OpenClaw thread handling, and activity panel layout for a more consistent chat and task experience. * **Agent planning and memory controls:** Added configurable retry and memory optimization settings in the UI and improved retry handling for deeper planning flows. * **Agent deployment readiness:** Agno-backed agents now warm up required tables automatically during deployment to reduce first-run issues. ## Bug Fixes: * **Safari chat composer sizing:** Fixed Safari iframe textarea sizing issues in hosted assistants for a more stable chat input experience. * **General platform fixes:** Included fixes for agent activity layout behavior, OpenClaw thread initialization, and other reliability issues across the platform. ## New Features: * **Revamped the Agent Studio experience:** Simplified the agent builder, improved the configuration panel and save/publish flows, added trace views so you can build, test, and monitor your agent invocations at the same time, and refreshed several navigation and card experiences. * **Voice input and output for agents:** Added microphone transcription in chat and a new voice output format so agents can return spoken responses. * **Audit logs for organizations:** Added centralized audit logging, audit APIs, and an admin audit log experience for tracking important organization events. * **Slack workflow support:** Added Slack workflow triggers, Slack integration panels, and structured JSON response handling for Slack workflow outputs. * **MongoDB connector and Redshift connector expansion:** Added a MongoDB functions controller and expanded Redshift capabilities with async execution, connection validation, stronger pagination, and clearer error handling. See connector docs here: [https://docs.xpander.ai/connectors](https://docs.xpander.ai/connectors) * **Agent notifications settings:** Added notification settings for agent execution outcomes, allowing the builder to configure a deterministic notification for every agent execution. * **Organization default LLM settings:** Added organization-level default LLM settings and applied them across new agents, workflows, and related creation flows. ## Improvements: * **OpenClaw and personal agent experience:** Improved OpenClaw onboarding, focused OpenClaw settings on instructions, added supervised agent indicators, and refined personal and supervised agent organization in the UI. * **Billing and admin UI polish:** Added a theme-aware billing portal and improved deploy and save interactions throughout the workbench. * **Agent container scheduling & metadata:** Tuned agent container resources, improved multi-AZ pod distribution, and exposed the supervision flag in minimal agent payloads. ## Bug Fixes: * **Agent card summaries:** Fixed agent cards in the agent list to use the latest general instructions text when available for the description of the agent. * **Various platform and UI fixes:** Included fixes for duplicate chat activity behavior, menu positioning, thread visibility for Agentic Workflows, and other reliability and usability issues. * **As always, our agents and humans continuously fix various bugs, and sometimes create new ones (that will be fixed in the next update.)** # New Product launch! **Introducing fully managed OpenClaw-based Personal AI Assistants:** Every employee in your organization now gets their own AI assistant — powered by OpenClaw, managed entirely by xpander. No setup, no configuration, no infrastructure to maintain. Each assistant lives where your team already works — Slack, Teams, or voice — and can act across any connected enterprise system through xpander's supervised specialized agents. IT deploys once; every employee gets a personalized, context-aware agent that delegates tasks, pulls data, and executes workflows on their behalf. It's not a chatbot that answers questions. It's an agent that does the work — governed by your policies, running on your infrastructure, and getting smarter with every interaction. ## New Features: * **OpenClaw agents (beta):** Added end-to-end OpenClaw integration, including a dedicated scaffold container, xpander↔OpenClaw bridge, plugin-based tool execution, and OpenClaw-specific health checks. * **OpenClaw onboarding and channel setup:** Added an onboarding wizard and workbench flows for OpenClaw container readiness and Telegram/Slack channel pairing and configuration. * **Cloudflare AI Gateway provider:** Added Cloudflare AI Gateway as an LLM provider option across agents, workflows, and workflow nodes. ## Improvements: * **Agent container reliability:** Migrated agent containers from Kubernetes Jobs to Deployments with PVC-backed persistent storage and added periodic health reconciliation. * **Sub-agent discovery:** Added a built-in capability for OpenClaw agents to discover and list available sub-agents from the agent graph. * **Workbench UX updates:** Renamed "Task sources" to "Channels", improved OpenClaw trigger UX, and enhanced activity/log views (including Markdown table rendering). * **Redshift ergonomics:** Added connector-level path parameters for cluster/database/catalog and increased Redshift statement execution timeout. ## Bug Fixes: * **Activity log pagination:** Fixed page ordering and navigation semantics so newer messages appear first and paging behaves consistently. * **As always, our agents and humans continuously fix various bugs.** ## New Features: * **Parallel workflow execution:** Added an explicit Parallel workflow node, enabling concurrent execution of multiple child nodes with configurable combined outputs. * **Paginated activity logs:** Introduced optional pagination for agent activity threads/tasks. * **Connector pipeline progress visibility:** Added connector pipeline step status updates and UI indicators (loading/shimmer and tooltips) while custom connectors are processing. * **Workflow test file uploads:** Enabled attaching files to workflow test runs and persisting them in test presets. ## Improvements: * **Workflow observability:** Enriched workflow events with resolved variables/conditions and deep parsing of stringified JSON outputs. * **Activity log durability:** Added asynchronous S3 synchronization for activity threads to improve retention and auditability. * **LLM default updates:** Updated default models to Claude Sonnet 4.6 and refreshed frontend/provider defaults to the latest Sonnet/Opus catalogs. * **AWS Neptune flexibility:** Added support for providing the Neptune endpoint via request body and improved endpoint normalization. ## Bug Fixes: * **Schema enforcement for summarizers:** Enforced strict JSON output schema for summarizer nodes and hardened file URL extraction from user input. * **As always, our agents and humans continuously fix various bugs.** ## New Features: * **Workflow authoring enhancements:** Added NodePointer ("Go to Existing") support, workflow result selection (choose which end node output becomes the workflow result), and surfaced workflow result in the execution console. ## New connectors: * **Microsoft Connectors:** Added new SharePoint and OneDrive connectors with site/drive discovery, recursive tree browsing, search, path resolution, file read/edit/create flows, agent-friendly content extraction. * **AWS Neptune connector:** Added an AWS Neptune connector with graph query execution (Gremlin/openCypher) and bulk loader operations. * **Google Cloud Monitoring**: Added support for Google Cloud Monitoring with metrics collection across GCP services, real-time alerting, uptime checks, and deep ecosystem integration, enabling AI agents to track system health, respond to alerts, and take action on live performance insights. See connector details at: [https://docs.xpander.ai/connectors](https://docs.xpander.ai/connectors) ## Improvements: * **Workflow orchestration reliability:** Hardened orchestration with DAG validation, improved routing/order determinism (including node reuse and parallel detection), and support for persisting agent task/thread IDs across orchestration runs. * **Activity & runs scalability:** Added optional pagination and infinite-scroll support for agent activity threads and workflow runs. * **BYOK transparency:** Marked BYOK usage in monitoring/activity and improved UI visibility so BYOK token usage is clearly distinguished. * **Managed vector DB search quality:** Improved large-document handling (chunking + export/delete semantics) and increased hybrid search reliability with full-text + vector ranking. * **AWS connection UX:** Improved AWS region selection with a searchable dropdown and refined workflow graph handle interactions. ## Bug Fixes: * **Agent execution resiliency:** Ensured the agent executor captures all base-level exceptions to reduce hard crashes. * **Other general bug fixes** # New Product launch! **Introducing Workflows:** A visual interface for orchestrating AI Agents and building automation workflows. We've eliminated the friction of traditional automation by **removing the need for tedious manual field mapping**. Instead of wiring up data inputs and outputs between steps, every node on the canvas is powered by an AI agent that understands the context of the previous step's output. Whether you're deploying an Email node or a Summarizer, you simply provide natural language instructions, and the agents handle the data flow for you. This gives you a deterministic, repeatable runtime with full control over execution and branching, without the overhead of mapping a single field. Read more in the docs: [https://docs.xpander.ai/guides/building-workflows/introduction](https://docs.xpander.ai/guides/building-workflows/introduction) ## New Features: * **Azure AI Foundry provider support:** Added Azure AI Foundry as an LLM provider (including required configuration for custom credentials and endpoint settings). * **LLM request customization:** Added organization-wide and per-agent support for default LLM extra headers. ## Improvements: * **LLM provider resilience:** Added exponential backoff retries across multiple LLM providers to better handle transient failures. * **Model catalog updates:** Refreshed Amazon Bedrock and Google AI Studio model catalogs and identifiers. * **Self-hosted environments: dash-based subdomains:** Added support for dash-based subdomain formats and centralized service URL construction. ## Bug Fixes: * **UI correctness:** Fixed issues in action/icon rendering, agent state flag updates, and sleep node identifier normalization. ## New Features: * **Pre-deploy change review:** Added a deployment comparison step that lets users review visual and JSON diffs between the staged and currently deployed agent before deploying. * **API trigger support and testing modal:** Added an API trigger option alongside Webhook, with a unified modal to test sync/async/stream invocations, generate curl commands, and view expanded responses. * **PDF document layout templates:** Added multiple PDF layout modes (whitepaper, invoice, letter, and order form with signature support) for markdown-to-PDF generation. * **Web search and text-to-speech tools:** Added built-in web search and text-to-speech tools. Enable them from the Tools tab in the AI Workbench. * **Agent reasoning visibility:** Improved reasoning step generation by deriving steps directly from activity threads and enhancing activity timeline rendering for JSON/Markdown with better duration formatting. ## Improvements: * **Webhook lifecycle hooks:** Added webhook lifecycle hooks (e.g., before, on-task-created, on-tool-call, on-error, after) with event streaming for richer integrations. * **User attribution via MCP auth:** Propagated MCP OAuth user context into agent invocations for more accurate user attribution. * **Locations management (renamed from Environments):** Renamed "Environments" to "Locations" and moved location management into Admin Settings. * **Webhook parameter mapping:** Added path-based parameter mapping for webhooks, with improved task ID parsing for UI rendering and clearer error handling. * **Container execution reliability:** Increased Docker runner memory limits and hardened log streaming and exit-code retrieval when containers are auto-removed. ## Bug Fixes: * **PDF rendering reliability and security:** Improved PDF typography and spacing, ensured reliable logo rendering by inlining images, and added URL validation/allowlisting and size limits for safer logo embedding. * **Hosted assistants UI rendering:** Fixed rendering of structured (JSON) sub-task descriptions and improved task step update stability. * **Custom functions reliability:** Stabilized custom functions typing/serialization and made analysis asynchronous for improved correctness. # Anchor Browser Source: https://docs.xpander.ai/connectors/anchor-browser Learn how to integrate AI agents with Anchor Browser using xpander.ai. Create intelligent AI agents that can browse the internet and complete complex tasks end-to-end. ## About Anchor Browser Anchor Browser is a programmable, cloud-based browser built for AI agents and automation software. Anchor Browser lets software and autonomous agents interact with the web exactly like a real human would, using a full Chromium environment, real network identities, and persistent state. Unlike traditional scraping or HTTP tools, Anchor Browser renders pages fully, executes JavaScript, solves modern web challenges, and performs multi-step workflows across real websites. ## Authentication Options Below are possible authentication options you can choose: ### Generate an Anchor Browser API Key 1. Log in to your [Anchor Browser account](https://app.anchorbrowser.io/). 2. Click **API Keys**. Img 1 3. Click **+ Add** on the top right corner of the **API Keys** page to create a new API key. 4. Enter a name for the new API key in the **Create New API Key** dialog that appears, and click **Continue** to create the new API key. Img 2 5. The new API key will appear in the API Keys page. Click the copy icon next to the API key to copy the generated key and store it somewhere safe. Img 3 ### Integrate Anchor Browser into xpander.ai 1. Go to the **Connectors** section in the sidebar of your xpander.ai dashboard. 2. Select **Anchor Browser** from the available integrations. 3. Click **Enable**. 4. Enter a **connector name** as desired, e.g., "xpander-anchorbrowser". 5. Select **Integration User** for the authentication mode. 6. Choose **API Key** as the authentication method. 7. Paste your Anchor Browser API key into the provided field. 8. Choose **Custom** as the auth type. 9. Enter **anchor-api-key** as the custom header name. 10. Enter **[https://api.anchorbrowser.io](https://api.anchorbrowser.io)** as the base URL in the Interface specific settings section. 11. Save the configuration. Img 4 ## Integration of Anchor Browser into an AI Agent Once you’ve configured your Anchor Browser connector with the authentication option(s) described above, you can integrate it into your AI agent with xpander.ai: 1. In your xpander.ai dashboard, navigate to the **Agents** page, then click an agent to open the **Agent Configuration** tab. 2. Select **Tools**, then click **Add Tools**. 3. Select **Connectors**. 4. Choose **Anchor Browser** with the same **connector name** you configured in the previous section (e.g., xpander-anchorbrowser). 5. Select the available Anchor Browser operations that suit your use case. To grant your agent web-browsing capabilities, enable the following operations. * **Create Browser Session** * **Fetch Rendered Webpage Content** Img 3 ## AI Agent Anchor Browser Prompt Library Below are possible prompts or use cases you can try after integrating Anchor Browser into your xpander.ai AI agent: ``` Visit Amazon, search for “wireless noise cancelling headphones,” and summarize the top 5 results by rating and price. ``` ``` Can you visit our competitor’s pricing page and tell me if anything has changed since last week? ``` ``` Go to LinkedIn, search for “Head of Engineering” roles in Berlin, and collect the first 20 company names. ``` ``` Open our CRM, find all leads created this week, and export them to a spreadsheet. ``` Gif 1 ## Related Resources * [Using Tools & Connectors in the xpander.ai platform](/guides/agents/tools-connectors) * [Anchor Browser Documentation](https://docs.anchorbrowser.io/introduction) # Apify Source: https://docs.xpander.ai/connectors/apify Learn how to integrate AI agents with Apify using xpander.ai. Create intelligent agents that can gather information from websites, monitor online content, and automate repetitive web tasks. ## About Apify **Apify** is a cloud-based web scraping and automation platform built for developers, AI agents, and data-driven applications. Apify enables software and autonomous agents to extract structured data from websites, run browser automation workflows, and operate large-scale crawling jobs without managing infrastructure. Unlike basic scraping scripts or manual crawlers, Apify provides a scalable execution environment with managed proxy rotation, distributed task processing, scheduling, and persistent storage. Developers can deploy reusable Actors (serverless automation units), orchestrate multi-step data-collection workflows, and programmatically access datasets via a robust API. ## Authentication Options Below are possible authentication options you can choose: ### Generate an Apify API Key 1. Log in to your [Apify account](https://console.apify.com/). 2. Select **Settings**, then click **API & Integrations**. Img 1 3. Click **+ Create a new token** to create a new API key. 4. Click **Create** in the dialog that appears to create your new API key.. Img 2 5. The new API key will appear on the page. Click the copy icon next to the API key to copy the generated key, then store it in a safe place.. Img 3 ### Integrate Apify into xpander.ai 1. Go to the **Connectors** section in the sidebar of your xpander.ai dashboard. 2. Select **Apify** from the available integrations. 3. Click **+ Create new connection**. 4. Enter a **connector name** as desired, e.g., "xpander-apify". 5. Choose **API Key** as the authentication method. 6. Paste your Apify access token into the provided field. 7. Choose **Bearer** as the **Auth Type**. 8. Save the configuration. Img 4 ## Integration of Apify into an AI Agent Once you’ve configured your Apify connector with the authentication option described above, you can integrate it into your AI agent with xpander.ai: 1. In your xpander.ai dashboard, navigate to the **Agents** page, then click an agent to open the **Agent Configuration** tab. 2. Select **Tools**, then click **Add Tools**. 3. Select **Connectors**. 4. Choose **Apify** with the same **connector name** you configured in the previous section (e.g., xpander-apify). 5. Select the available Apify operations that suit your use case. To grant your agent web scraping capabilities, enable the following operations. * **Start Actor Run** * **List Actor Runs (By Actor)** * **Get Actor Last Run** * **Create Actor** * **List Actors** 6. Click **Deploy** to update your agent. Img 3 ## AI Agent Apify Prompt Library Below are possible prompts or use cases you can try after integrating Apify into your xpander.ai AI agent: ``` Run a web scraping task to extract the top 10 results for “wireless noise cancelling headphones” from Amazon, including price and rating. ``` ``` Check our competitor’s pricing page and report any changes in pricing or plans compared to the last saved dataset. ``` ``` Collect the first 20 LinkedIn job listings for “Head of Engineering” in Berlin and return the company names. ``` ``` Monitor daily and notify me if new content is published. ``` Gif 1 ## Related Resources * [Using Tools & Connectors in the xpander.ai platform](/guides/agents/tools-connectors) * [Apify Documentation](https://docs.apify.com/) # Asana Source: https://docs.xpander.ai/connectors/asana Learn how to integrate AI agents with Asana using xpander.ai. Create intelligent workflows that automate routine tasks, assign responsibilities, and provide real-time insights to enhance team productivity and decision-making. ## About Asana Asana is a web-based and mobile work management platform designed to help teams organize, track, and manage their work. Asana key features: * **Task and Project Management**: Asana allows teams to create projects, assign tasks, set deadlines, and track progress. Users can organize work using various views such as lists, boards, calendars, and timelines. * **Collaboration Tools**: Team members can communicate directly within tasks through comments, share files, and receive notifications, facilitating seamless collaboration. * **Reporting and Analytics**: Asana provides real-time reporting features, enabling teams to gain insights into project statuses and identify potential risks or bottlenecks. * **Integrations**: The platform integrates with various third-party applications, including Google Workspace, Figma, and Zoom, enhancing its functionality and adaptability to different workflows. * **AI Capabilities**: In recent developments, Asana has introduced AI features like "AI teammates," which assist users by performing tasks, setting up triggers, and providing work analysis through a chatbot interface. ## Authentication Options Below are possible authentication options you can choose: ### Generate an Asana API Key 1. Log in to your [Asana developer console](https://app.asana.com/0/my-apps). 2. Click **Create New Token** and give your token a name. Img 1 3. Your access token will be displayed—make sure to copy and store it securely. ### Integrate Asana into xpander.ai 1. In your xpander.ai dashboard, go to the **Connectors** section in the sidebar. 2. Select **Asana** from the list of available integrations. 3. Click **Other auth options**. 4. Enter a **connector name**, e.g., "xpander-asana". 5. Select **Integration User** for the authentication mode. 6. Choose **API Key** as the authentication method. 7. Paste your Asana access token into the provided field. 8. Set the **Auth Type** to **Bearer**. 9. Save the configuration. Img 2 ## Integration of Asana into AI Agent Once you've configured your Asana account with the authentication option(s) described above, you can integrate it into your AI agent with xpander.ai: 1. In your xpander.ai dashboard, go to the **Agent Configuration** tab and select **Tools**, then click **Add Tools**. 2. Select **Connectors**. 3. Choose **Asana** with the same **connector name** you configured in the previous section (e.g., xpander-asana). 4. Select the available Asana operations that suit your use case. Img 3 ## Expose Asana as MCP Server Alternatively, you can also expose your Asana account as an MCP server. To do so: 1. In your **xpander.ai** dashboard, navigate to the **Connectors** section in the sidebar. 2. Select **Asana** with the same **connector name** you configured in the previous section (e.g., xpander-asana). 3. Click **MCP Configuration**. 4. Enter the MCP configuration into the appropriate settings of the client app you want to use (e.g., Cursor, Windsurf, Claude Desktop, etc.). Img 4 ## AI Agent Asana Prompt Library Below are possible prompts or use cases you can try after integrating Asana into your xpander AI agent: ``` Could you create a new goal for Q3 titled "{goal_name}" and link it to our current objectives? ``` ``` Can you upload the latest {document_name} brief to our project and notify the team? ``` ``` Could you create a new project from our {template_name} template and set the due date to {date}? ``` ``` Can you add {user_name} to the {project_name} project team and give them editor access? ``` ## Related Resources * [Understanding Model Context Protocol (MCP)](/guides/deploy/mcp) * [Asana API Documentation](https://developers.asana.com/reference/rest-api-reference) # Calendly Source: https://docs.xpander.ai/connectors/calendly Learn how to integrate AI agents with Calendly using xpander.ai. Create intelligent scheduling workflows that automatically coordinate meetings, personalize communication, and adapt to real-time changes. ## About Calendly Calendly is an online scheduling tool that helps individuals and businesses streamline the process of setting up meetings and appointments. Instead of the back-and-forth emails to find a mutually available time, Calendly allows users to: * Share a personalized link with others (e.g., calendly.com/yourname) * Let invitees book time based on the user's availability * Sync with calendars like Google, Outlook, or iCloud to avoid double-booking ## Authentication Options Below are possible authentication options you can choose: The simplest way to connect Calendly is by using xpander.ai's built-in authentication: 1. Go to the **Connectors** section in the sidebar of your xpander.ai dashboard. 2. Select **Calendly** from the available integrations. 3. Click **Sign in with Calendly**. 4. Grant xpander.ai permission to access your account. 5. Your Calendly integration is now ready to use. ### Generate a Calendly API Key 1. Log in to your [Calendly account](https://calendly.com/). 2. Click on **Integrations & apps** in the sidebar. 3. Click on **API and webhooks**.\\ Img 1 4. Click **Get a token now**. 5. Enter a name for your token, then click **Create token**. 6. Save the access token. ### Integrate Calendly into xpander.ai 1. Go to the **Connectors** section in the sidebar of your xpander.ai dashboard. 2. Select **Calendly** from the available integrations. 3. Click **Other auth options**. 4. Enter a **connector name**, e.g., "xpander-calendly". 5. Select **Integration User** as the authentication mode. 6. Select **API Key** as the authentication method. 7. Paste the Calendly access token into the provided field. 8. Choose **Bearer** as the **Auth Type**. 9. In the **Interface specific settings** section, enter `https://api.calendly.com/` as the base URL. 10. Save the configuration. Img 2 ## Integration of Calendly into AI Agent Once you've configured your Calendly account with the authentication option(s) described above, you can integrate it into your AI agent with xpander.ai: 1. In your xpander.ai dashboard, go to the **Agent Configuration** tab and select **Tools**, then click **Add Tools**. 2. Select **Connectors**. 3. Choose **Calendly** with the same **connector name** you configured in the previous section (e.g., xpander-calendly). 4. Select the available Calendly operations that suit your use case. Img 3 ## Expose Calendly as MCP Server Alternatively, you can also expose your Calendly account as an MCP server. To do so: 1. Go to the **Connectors** section in the sidebar of your xpander.ai dashboard. 2. Select **Calendly** with the same **connector name** you configured in the previous section (e.g., xpander-calendly). 3. Click **MCP Configuration**. 4. Enter the MCP configuration into the appropriate settings of the client app you want to use (e.g., Cursor, Windsurf, Claude Desktop, etc.). Img 4 ## AI Agent Calendly Prompt Library Below are possible prompts or use cases you can try after integrating Calendly into your xpander AI agent: ``` Can you show me all my scheduled events for next week? ``` ``` Could you create a one-time scheduling link for the {project_name} consultation with {client_name}? ``` ``` When is {team_member} available between {start_date} and {end_date}? ``` ``` Who are all the hosts assigned to our {event_type_name} event? ``` ## Related Resources * [Understanding Model Context Protocol (MCP)](/guides/deploy/mcp) * [Calendly API Documentation](https://developer.calendly.com/api-docs/4b402d5ab3edd-calendly-developer) # Clickup Source: https://docs.xpander.ai/connectors/clickup Learn how to integrate AI agents with ClickUp using xpander.ai. Create automated workflows that leverage AI to streamline task management, generate smart task summaries, and boost team productivity. ## About ClickUp ClickUp is a comprehensive project management and productivity platform designed to centralize tasks, collaboration, documentation, and communication in a single interface. Key features include: * **Task Management**: Organize work using customizable tasks, subtasks, checklists, and over 35 ClickApps (e.g., time tracking, custom fields, sprint points). * **Multiple Views**: Choose from 15+ views, including List, Board, Calendar, Gantt, Timeline, Whiteboard, and Table, to visualize and manage projects from different perspectives. * **Automation**: Set up conditional workflows with if-then logic to automate repetitive tasks, such as status changes or task assignments. * **Collaboration Tools**: Utilize built-in chat, whiteboards, and real-time document editing to facilitate team communication and brainstorming. * **AI Integration**: ClickUp Brain, introduced in 2024, offers AI-powered features like task summarization, content generation, and intelligent search across tasks and documents. ## Authentication Options Below are possible authentication options you can choose: The simplest way to connect ClickUp is by using xpander.ai's built-in authentication: 1. Go to the **Connectors** section in the sidebar of your xpander.ai dashboard. 2. Select **ClickUp** from the available integrations. 3. Click **Sign in with ClickUp**. 4. Grant xpander.ai permission to access your ClickUp workspace. 5. Your ClickUp integration is now ready to use. ### Generate a ClickUp API Key 1. Log in to your [ClickUp account](https://app.clickup.com/). 2. Click on your account icon in the top-right corner and select **Settings**.\\ Img 1 3. In the sidebar, go to **Connectors** and click **Generate**.\\ Img 2 4. You'll now see your ClickUp API key—copy and store it safely. ### Integrate ClickUp into xpander.ai 1. Go to the **Connectors** section in the sidebar of your xpander.ai dashboard. 2. Select **ClickUp** from the available integrations. 3. Click **Enable**. 4. Enter a **connector name**, e.g., xpander-clickup. 5. Select **Integration User** as the authentication mode. 6. Select **API Key** as the authentication method. 7. Paste your ClickUp API key into the provided field. 8. Choose **Custom** as the **Auth Type**. 9. In the **Custom header name** field, enter: `Authorization`. 10. Save the configuration. Img 3 ## Integration of ClickUp into AI Agent Once you've configured your ClickUp account with the authentication option(s) described above, you can integrate it into your AI agent with xpander.ai: 1. In your xpander.ai dashboard, go to the **Agent Configuration** tab and select **Tools**, then click **Add Tools**. 2. Select **Connectors**. 3. Choose **ClickUp** with the same **connector name** you configured in the previous section (e.g., xpander-clickup). 4. Select the available ClickUp operations that suit your use case. Img 4 ## Expose ClickUp as MCP Server Alternatively, you can also expose your ClickUp account as an MCP server. To do so: 1. Go to the **Connectors** section in the sidebar of your xpander.ai dashboard. 2. Select **ClickUp** with the same **connector name** you configured in the previous section (e.g., xpander-clickup). 3. Click **MCP Configuration**. 4. Enter the MCP configuration into the appropriate settings of the client app you want to use (e.g., Cursor, Windsurf, Claude Desktop, etc.). Img 5 ## AI Agent ClickUp Prompt Library Below are possible prompts or use cases you can try after integrating ClickUp into your xpander AI agent: ``` Can you add a comment to the task {task_name} saying '{comment_text}'? ``` ``` Can you schedule a reminder for the task {task_name} on {date}? ``` ``` Can you mark the task {task_name} as completed? ``` ``` Can you create a new folder named {folder_name} in the space {space_name}? ``` ## Related Resources * [Understanding Model Context Protocol (MCP)](/guides/deploy/mcp) * [ClickUp API Documentation](https://developer.clickup.com/reference/) # Confluence Source: https://docs.xpander.ai/connectors/confluence Learn how to integrate AI agents with Confluence using xpander.ai. Create intelligent workflows that automate documentation, generate dynamic content, and surface relevant knowledge across your Confluence spaces using AI-powered agents. ## About Confluence Confluence is a collaborative workspace developed by Atlassian, designed to help teams create, organize, and share knowledge efficiently. It serves as a central hub where teams can collaborate on projects, document processes, and maintain institutional knowledge. Key features include: * **Dynamic Pages**: Confluence allows users to create and edit pages collaboratively, making it easy to document meeting notes, project plans, and other important information. * **Organized Spaces**: Content is structured into spaces, which can be organized by team, project, or department, facilitating easy navigation and information retrieval. * **Integration with Atlassian Tools**: Confluence integrates seamlessly with other Atlassian products like Jira, enhancing project tracking and collaboration. * **Templates and Macros**: It offers a variety of templates and macros to streamline content creation and formatting. * **Access Controls**: Granular permission settings ensure that sensitive information is accessible only to authorized users. ## Authentication Options Below are possible authentication options you can choose: The simplest way to connect to Confluence is by using xpander.ai's built-in authentication: 1. Go to the **Agentic Connectors** section in the sidebar of your xpander.ai dashboard. 2. Select **Confluence** from the available integrations. 3. Click **+ Create new connection**. 4. Enter a **connector name** as desired, e.g., "xpander-confluence". 5. Choose **OAuth2** as the authentication method. 6. Click **Authorize xpander.ai**. 7. Grant xpander.ai permission to access your account. 8. Save the configuration. Img 2 ## Integration of Confluence into AI Agent Once you've configured your Confluence account with the authentication option(s) described above, you can integrate it into your AI agent with xpander.ai: 1. In your xpander.ai dashboard, go to the **Agent Configuration** tab and select **Tools**, then click **Add Tools**. 2. Select **Connectors**. 3. Choose **Confluence** with the same **connector name** you configured in the previous section (e.g., xpander-confluence). 4. Select the available Confluence operations that suit your use case. To grant your agent space management capabilities, enable the following operations. * **Get All Spaces** * **Get Space By ID** * **Get Space Pages** * **Get Space Blog Posts** * **Get Space Operations** 5. Click **Save**, then click **Publish** to publish the updated agent. Img 3 ## AI Agent Confluence Prompt Library Below are possible prompts or use cases you can try after integrating Confluence into your xpander AI agent: ``` I need to see who liked the feedback comment on our project proposal, can you check? ``` ``` I need to update the property {property_name} on our project blog post, can you help? ``` ``` Can you fetch all the inline comments on the {page_name} documentation to review feedback? ``` ``` Can you help me find all attachments in our Confluence site? ``` GIF 1 ## Related Resources * [Understanding Model Context Protocol (MCP)](/guides/deploy/mcp) * [Confluence API Documentation](https://developer.atlassian.com/cloud/confluence/rest/v2/intro/#about) # Datadog Source: https://docs.xpander.ai/connectors/datadog Learn how to integrate AI agents with Datadog using xpander.ai. Create intelligent observability workflows that automatically detect anomalies, correlate incidents across your stack, and trigger remediation actions. ## About Datadog Datadog offers a Software-as-a-Service (SaaS) platform that provides observability across an organization's entire technology stack. Key features include: * **Infrastructure Monitoring**: Real-time tracking of servers, containers, databases, and cloud services. * **Application Performance Monitoring (APM)**: End-to-end tracing and diagnostics for applications. * **Log Management**: Centralized logging with search and analytics capabilities. * **Security Monitoring**: Threat detection and compliance monitoring. * **User Experience Monitoring**: Frontend performance metrics and session data. * **Network Monitoring**: Visibility into network traffic and device performance. ## Authentication Options Below are possible authentication options you can choose: ### Generate a Datadog API Key 1. Log in to your [Datadog account](https://app.datadoghq.com/). Make sure you log in to the correct Datadog region for your account. 2. In the sidebar, click on **Go to**, type **API Keys**, and select **API Keys** from the search results. Img 1 3. You’ll now see the API keys for your Datadog account. Img 2 4. To access the Datadog API, you’ll also need an application key. 5. In the sidebar, click on **Application Keys**, then click **New Key**. 6. Give your key a name and assign the necessary scopes based on your use case. Img 3 ### Integrate Datadog into xpander.ai 1. In your xpander.ai dashboard, go to the **Connectors** section in the sidebar. 2. Select **Datadog** from the available integrations. 3. Click **Enable**. 4. Enter a **connector name**, e.g., "xpander-datadog". 5. Choose **Integration User** as the authentication mode. 6. Select **API Key** as the authentication method. 7. Paste your Datadog API key into the provided field. 8. Set the **Auth Type** to **Custom**. 9. In the **Custom header name** field, enter `DD-API-KEY`. 10. Paste your Datadog application key into the **DD-APPLICATION-KEY** field. 11. Under **Interface specific settings**, enter the base URL: `https://api.datadoghq.{domain}/`, replacing with the domain corresponding to your Datadog account region. 12. Save the configuration. Img 4 ## Integration of Datadog into AI Agent Once you've configured your Datadog account with the authentication option(s) described above, you can integrate it into your AI agent with xpander.ai: 1. In your xpander.ai dashboard, go to the **Agent Configuration** tab and select **Tools**, then click **Add Tools**. 2. Select **Connectors**. 3. Choose **Datadog** with the same **connector name** you configured in the previous section (e.g., xpander-datadog). 4. Select the available Datadog operations that suit your use case. Img 5 ## Expose Datadog as MCP Server Alternatively, you can also expose your Datadog account as an MCP server. To do so: 1. Go to the **Connectors** section in the sidebar of your xpander.ai dashboard. 2. Select **Datadog** with the same **connector name** you configured in the previous section (e.g., xpander-datadog). 3. Click **MCP Configuration**. 4. Enter the MCP configuration into the appropriate settings of the client app you want to use (e.g., Cursor, Windsurf, Claude Desktop, etc.). Img 6 ## AI Agent Datadog Prompt Library Below are possible prompts or use cases you can try after integrating Datadog into your xpander AI agent: ``` Could you create a new dashboard for monitoring {application_name} performance metrics? ``` ``` Can you set up a monitor to alert us when {service_name} latency exceeds {threshold_value} milliseconds? ``` ``` Could you temporarily mute alerts for {host_name} during our scheduled maintenance window on {date}? ``` ``` Could you integrate our AWS {account_name} account to monitor our EC2 and Lambda resources? ``` ## Related Resources * [Understanding Model Context Protocol (MCP)](/guides/deploy/mcp) * [Datadog API Documentation](https://docs.datadoghq.com/api/latest/?tab=java) # dbt Labs Source: https://docs.xpander.ai/connectors/dbt-labs Learn how to integrate AI agents with dbt Labs using xpander.ai. Create intelligent workflows that automate data transformation, generate insights, and enhance analytics efficiency seamlessly within your data pipeline. ## About dbt Labs dbt (Data Build Tool) is an open-source and cloud platform that enables analytics engineers to transform raw data into clean, documented, and tested datasets directly in their cloud warehouses using SQL and software engineering best practices. Key features include: * **SQL‑based modeling**: Build modular, versioned SQL models in any cloud data warehouse (Snowflake, BigQuery, Redshift, Databricks) * **Documentation & lineage**: Auto‑generated docs, searchable metadata, lineage graphs for transparency and governance. * **Orchestration & scheduling**: Built‑in job scheduler, run history, run visibility, alerting and Slack/email integrations. * **Semantic Layer**: Centralized and consistent metric definitions surfaced to dashboards or LLMs (Enterprise tier). * **dbt Mesh**: Handles data dependencies across business domains, multi‑team orchestration. ## Authentication Options Below are possible authentication options you can choose: ### Generate a dbt Labs API Token 1. Log in to your [dbt Labs account](https://auth.cloud.getdbt.com/u/login). 2. At the bottom of the sidebar in your dashboard, click your profile and select **Your profile**. Img 1 3. In the sidebar, choose **Personal tokens**, then click **Create personal access token**. Img 2 4. Enter a name for your access token, then click **Save**. 5. Copy your personal access token and store it securely before closing the dialog box. ### Integrate dbt Labs into xpander.ai 1. In your xpander.ai dashboard, go to the **Connectors** section in the sidebar. 2. Select **dbt Labs** from the available integrations. 3. Click **Enable**. 4. Enter a **connector name**, e.g., "xpander-dbt-labs". 5. Choose **Integration User** as the authentication mode. 6. Select **API Key** as the authentication method. 7. Paste your dbt Labs access token into the provided field. 8. Set the **Auth Type** to **Bearer**. 9. Under **Interface specific settings**, enter the base URL: `https://{url}/`, replacing with the URL of your dbt Labs account. You can find the URL of your dbt account by clicking **Account** -> **Access URL** in the same page where you created your personal access token before. Img 3 10. Save the configuration. Img 4 ## Integration of dbt Labs into AI Agent Once you've configured your dbt Labs account with the authentication option(s) described above, you can integrate it into your AI agent with xpander.ai: 1. In your xpander.ai dashboard, go to the **Agent Configuration** tab and select **Tools**, then click **Add Tools**. 2. Select **Connectors**. 3. Choose **dbt Labs** with the same **connector name** you configured in the previous section (e.g., xpander-dbt-labs). 4. Select the available dbt Labs operations that suit your use case. Img 5 ## Expose dbt Labs as MCP Server Alternatively, you can also expose your dbt Labs account as an MCP server. To do so: 1. Go to the **Connectors** section in the sidebar of your xpander.ai dashboard. 2. Select **dbt Labs** with the same **connector name** you configured in the previous section (e.g., xpander-dbt-labs). 3. Click **MCP Configuration**. 4. Enter the MCP configuration into the appropriate settings of the client app you want to use (e.g., Cursor, Windsurf, Claude Desktop, etc.). Img 6 ## AI Agent dbt Labs Prompt Library Below are possible prompts or use cases you can try after integrating dbt Labs into your xpander AI agent: ``` Create a new SCIM user with username '{username}' and email '{email_address}' in account {account_id}. ``` ``` Retrieve all collections from the business intelligence tool for lineage integration {integration_id} in project {project_id} and get details for collection {collection_id}. ``` ``` Can you create a new Git repository for project {project_id} in account {account_id}? ``` ``` Generate a CSV export of all audit logs for account {account_id} from the past {time_period}. ``` ## Related Resources * [Understanding Model Context Protocol (MCP)](/guides/deploy/mcp) * [dbt Labs API Documentation](https://docs.getdbt.com/dbt-cloud/api-v2#/) # Dropbox Source: https://docs.xpander.ai/connectors/dropbox Learn how to integrate AI agents with Dropbox using xpander.ai. Create intelligent agents that automatically organize, analyze, and act on your files, whether it's summarizing documents, tagging images, or triggering actions based on file updates. ## About Dropbox Dropbox is a cloud-based file storage and collaboration platform that allows users to: * Store files online instead of (or in addition to) their local device. * Sync files across multiple devices (PCs, phones, tablets). * Share files or folders with others easily via links or access permissions. * Collaborate on documents, especially with features like Dropbox Paper and integrations with tools like Google Workspace and Microsoft Office. ## Authentication Options Below are possible authentication options you can choose: ### Generate Dropbox Access Token 1. Go to your [Dropbox app console](https://www.dropbox.com/developers/apps). 2. Click **Create app**. 3. Set up and configure the scope of the app to your liking. Once you're done, click **Create app**.\\ Img 1 4. Once the app has been created, navigate to the **OAuth 2** section. 5. Under **Generated access token**, click **Generate**, and you'll see your access token.\\ Img 2 ### Integrate Dropbox into Xpander.ai 1. Go to the **Connectors** section in the sidebar of your xpander.ai dashboard. 2. Select **Dropbox** from the available integrations. 3. Click **Enable**. 4. Fill in the **connector name** as desired, e.g., "xpander-dropbox". 5. Choose **Integration user** as the authentication mode. 6. Choose **API Key** as the authentication method. 7. Copy and paste your Dropbox access token into the provided field. 8. Choose **Bearer** as the **auth type**. 9. Save the configuration. Img 3 ## Integration of Dropbox into AI Agent Once you've configured your Dropbox account with the authentication option(s) described above, you can integrate it into your AI agent with xpander.ai: 1. In your xpander.ai dashboard, go to the **Agent Configuration** tab and select **Tools**, then click **Add Tools**. 2. Select **Connectors**. 3. Choose **Dropbox** with the same **connector name** you configured in the previous section (e.g., xpander-dropbox). 4. Select the available Dropbox operations that suit your use case. Img 4 ## Expose Dropbox as MCP Server Alternatively, you can also expose your Dropbox account as an MCP server. To do so: 1. Go to the **Connectors** section in the sidebar of your xpander.ai dashboard. 2. Select **Dropbox** with the same **connector name** you configured in the previous section (e.g., xpander-dropbox). 3. Click **MCP Configuration**. 4. Put the MCP configuration into the appropriate settings of the client app you want to use (e.g., Cursor, Windsurf, Claude Desktop, etc.). Img 5 ## AI Agent Dropbox Prompt Library Below are possible prompts or use cases you can try after integrating Dropbox into your xpander AI agent: ``` Can you remove all the contacts I manually added from {source_name}? ``` ``` Can you delete only the contacts with email addresses from {domain_name}? ``` ``` Can you list all files in the {folder_name} folder? ``` ``` Can you show me the shared link for {filename}? ``` ## Related Resources * [Understanding Model Context Protocol (MCP)](/guides/deploy/mcp) * [Dropbox API Documentation](https://www.dropbox.com/developers/documentation/http/documentation) # Fibery Source: https://docs.xpander.ai/connectors/fibery Learn how to integrate AI agents with Fibery using xpander.ai. Create intelligent workflows that automate routine tasks, extract actionable insights from unstructured data like customer feedback, and trigger updates across your workspace. ## About Fibery Fibery is a no-code platform that allows organizations to build custom workspaces tailored to their unique needs. It enables teams to define their own data structures, establish relationships between them, and visualize information through customizable views like boards, timelines, calendars, and reports. Fibery key features: * **Customizable Data Structures**: Define your own entities (e.g., Projects, Tasks, Bugs) and their relationships. * **Visual Workspaces**: Use Kanban boards, calendars, timelines, and tables to manage and visualize work. * **Collaborative Documents**: Create and edit rich-text documents with real-time collaboration. * **Whiteboards**: Brainstorm and map out ideas visually. * **Automation Rules**: Set up custom workflows and triggers to automate routine tasks. * **AI Integration**: Leverage AI to extract insights from feedback and automate content creation. * **Integrations**: Connect with external tools like GitHub, Jira, Slack, Intercom, and more. ## Authentication Options Below are possible authentication options you can choose: ### Generate a Fibery API Key 1. Log in to your [Fibery workspace](https://fibery.io/login). Img 1 2. Click your username at the top-left of your dashboard, then select **Settings**. 3. In the sidebar, go to the **API Keys** section and click **Generate API key**. 4. Your API key is now ready to use. Img 2 ### Integrate Fibery into xpander.ai 1. In your xpander.ai dashboard, go to the **Connectors** section in the sidebar. 2. Select **Fibery** from the available integrations. 3. Click **Enable**. 4. Enter a **connector name**, e.g., "xpander-fibery". 5. Select **Integration User** for the authentication mode. 6. Choose **API Key** as the authentication method. 7. Paste your Fibery API key into the provided field. 8. Set the **Auth Type** to **Custom**. 9. In the **Custom header name** field, enter: `Authorization: Token`. 10. Save the configuration. Img 3 ## Integration of Fibery into AI Agent Once you've configured your Fibery account with the authentication option(s) described above, you can integrate it into your AI agent with xpander.ai: 1. In your xpander.ai dashboard, go to the **Agent Configuration** tab and select **Tools**, then click **Add Tools**. 2. Select **Connectors**. 3. Choose **Fibery** with the same **connector name** you configured in the previous section (e.g., xpander-fibery). 4. Select the available Fibery operations that suit your use case. Img 4 ## Expose Fibery as MCP Server Alternatively, you can also expose your Fibery account as an MCP server. To do so: 1. Go to the **Connectors** section in the sidebar of your xpander.ai dashboard. 2. Select **Fibery** with the same **connector name** you configured in the previous section (e.g., xpander-fibery). 3. Click **MCP Configuration**. 4. Enter the MCP configuration into the appropriate settings of the client app you want to use (e.g., Cursor, Windsurf, Claude Desktop, etc.). Img 5 ## AI Agent Fibery Prompt Library Below are possible prompts or use cases you can try after integrating Fibery into your xpander AI agent: ``` Can we create a new feature request titled "{feature_title}" in our Product Backlog? ``` ``` Can you show me all the tasks assigned to {assignee_name} with a "High" priority? ``` ``` Can you rename the "Due Date" field to "Deadline" in our Tasks database? ``` ``` Could you show me the current schema of our {workspace_name} workspace to help with our database planning? ``` ## Related Resources * [Understanding Model Context Protocol (MCP)](/guides/deploy/mcp) * [Fibery API Documentation](https://the.fibery.io/@public/User_Guide/Guide/Fibery-API-overview-279) # Github Actions Manager Source: https://docs.xpander.ai/connectors/github-actions-manager Learn how to integrate AI agents with GitHub Actions Manager using xpander.ai. Create dynamic, event-driven workflows where agents can trigger, monitor, and manage Actions workflows in real time. ## About Github Actions Manager GitHub is a cloud-based platform designed for developers to store, manage, and collaborate on code. GitHub Actions, enabling developers to automate workflows, manage runners, handle artifacts, and more. Key features of Github Actions Manager include: * **Workflows**: Manage and control workflow configurations within a repository. * **Workflow Runs**: Track, re-run, cancel, or delete specific executions of workflows. * **Jobs**: Inspect and monitor individual jobs within a workflow run, including logs. * **Artifacts**: Handle generated build artifacts—list, download, or delete them as needed. * **Secrets**: Securely manage sensitive values (like tokens) used in workflows. * **Variables**: Store and manage non-sensitive config values for workflows. * **Runners**: Manage GitHub-hosted or self-hosted machines that execute workflows. * **Permissions**: Control what actions and workflows are allowed and who can run them. ## Authentication Options Below are possible authentication options you can choose: The simplest way to connect Github Actions Manager is by using xpander.ai's built-in authentication: 1. Go to the **Connectors** section in the sidebar of your xpander.ai dashboard. 2. Select **Github Actions Manager** from the available integrations. 3. Click **Sign in with Github Actions Manager**. 4. Grant xpander.ai permission to access your Github workspace. 5. Your Github Actions Manager integration is now ready to use. ### Generate a Github Actions Manager API Key 1. Log in to your [Github account](https://github.com/). 2. Click your profile icon in the top-right corner and select **Settings**.\\ Img 1 3. In the sidebar, click **Developer settings**. 4. Select **Personal access tokens**, then click on **Tokens (classic)**. 5. Click **Generate new token**, then select **Generate new token (classic)**.\\ Img 2 6. Add a description under **Note**, set an expiration date, and choose the appropriate scopes for your token. 7. After clicking **Generate token**, you’ll see your Github access token—be sure to copy and store it securely. ### Integrate Github Actions Manager into xpander.ai 1. Go to the **Connectors** section in the sidebar of your xpander.ai dashboard. 2. Select **Github Actions Manager** from the available integrations. 3. Click **Other auth options**. 4. Enter a **connector name**, e.g., "xpander-github-actions-manager". 5. Select **Integration User** as the authentication mode. 6. Select **API Key** as the authentication method. 7. Paste the Github access token into the provided field. 8. Choose **Bearer** as the **Auth Type**. 9. Save the configuration.\\ Img 3 ## Integration of Github Actions Manager into AI Agent Once you've configured your Github Actions Manager account with the authentication option(s) described above, you can integrate it into your AI agent with xpander.ai: 1. In your xpander.ai dashboard, go to the **Agent Configuration** tab and select **Tools**, then click **Add Tools**. 2. Select **Connectors**. 3. Choose **Github Actions Manager** with the same **connector name** you configured in the previous section (e.g., xpander-github-actions-manager). 4. Select the available Github Actions Manager operations that suit your use case. Img 4 ## Expose Github Actions Manager as MCP Server Alternatively, you can also expose your Github Actions Manager account as an MCP server. To do so: 1. Go to the **Connectors** section in the sidebar of your xpander.ai dashboard. 2. Select **Github Actions Manager** with the same **connector name** you configured in the previous section (e.g., xpander-github-actions-manager). 3. Click **MCP Configuration**. 4. Enter the MCP configuration into the appropriate settings of the client app you want to use (e.g., Cursor, Windsurf, Claude Desktop, etc.). Img 5 ## AI Agent Github Actions Manager Prompt Library Below are possible prompts or use cases you can try after integrating Github Actions Manager into your xpander AI agent: ``` Can you provide the job details for job ID {job_id} in {repository_owner}/{repository_name}? ``` ``` Can you delete the artifact with ID {artifact_id} from {repository_owner}/{repository_name}? ``` ``` Can you cancel the workflow run with ID {run_id} in {repository_owner}/{repository_name}? ``` ``` Can you rerun the job with ID {job_id} in {repository_owner}/{repository_name} with debug logging enabled? ``` ## Related Resources * [Understanding Model Context Protocol (MCP)](/guides/deploy/mcp) * [Github Actions Manager API Documentation](https://docs.github.com/en/rest/actions/) # Github Issues Manager Source: https://docs.xpander.ai/connectors/github-issues-manager Learn how to integrate AI agents with GitHub Issues Manager using xpander.ai. Create intelligent automation pipelines that monitor, generate, and triage issues in real time. ## About Github Issues Manager GitHub is a cloud-based platform designed for developers to store, manage, and collaborate on code. Key features of Github Issues Manager include: * **List Issues**: Retrieve issues assigned to the authenticated user across all visible repositories, including owned, member, and organization repositories. Filters such as assigned, created, mentioned, subscribed, repos, or all can be applied to narrow down results. * **Create an Issue**: Initiate a new issue in a specified repository by providing necessary details like title, body, and labels. * **Get an Issue**: Fetch detailed information about a specific issue using its number within a repository. * **Update an Issue**: Modify attributes of an existing issue, such as title, body, state (open or closed), labels, and assignees. * **Lock/Unlock an Issue**: Restrict or allow further comments on an issue to manage discussions effectively. ## Authentication Options Below are possible authentication options you can choose: The simplest way to connect Github Issues Manager is by using xpander.ai's built-in authentication: 1. Go to the **Connectors** section in the sidebar of your xpander.ai dashboard. 2. Select **Github Issues** from the available integrations. 3. Click **Sign in with Github Issues**. 4. Grant xpander.ai permission to access your Github workspace. 5. Your Github Issues Manager integration is now ready to use. ### Generate a Github Issues Manager API Key 1. Log in to your [Github account](https://github.com/). 2. Click your profile icon in the top-right corner, then select **Settings**.\\ Img 1 3. In the sidebar, navigate to **Developer settings**. 4. Select **Personal access tokens**, then click on **Tokens (classic)**. 5. Click **Generate new token**, then choose **Generate new token (classic)**.\\ Img 2 6. Add a description under the **Note** field, set an expiration date, and choose the appropriate scopes for your token. 7. Click **Generate token**. You’ll then see your Github access token—make sure to copy and store it securely. ### Integrate Github Issues Manager into xpander.ai 1. Go to the **Connectors** section in the sidebar of your xpander.ai dashboard. 2. Select **Github Issues** from the available integrations. 3. Click **Other auth options**. 4. Enter a **connector name**, e.g., "xpander-github-issues-manager". 5. Select **Integration User** as the authentication mode. 6. Select **API Key** as the authentication method. 7. Paste the Github access token into the provided field. 8. Choose **Bearer** as the **Auth Type**. 9. Save the configuration.\\ Img 3 ## Integration of Github Issues Manager into AI Agent Once you've configured your Github Issues Manager account with the authentication option(s) described above, you can integrate it into your AI agent with xpander.ai: 1. In your xpander.ai dashboard, go to the **Agent Configuration** tab and select **Tools**, then click **Add Tools**. 2. Select **Connectors**. 3. Choose **Github Issues Manager** with the same **connector name** you configured in the previous section (e.g., xpander-github-issues-manager). 4. Select the available Github Issues Manager operations that suit your use case. Img 4 ## Expose Github Issues Manager as MCP Server Alternatively, you can also expose your Github Issues Manager account as an MCP server. To do so: 1. Go to the **Connectors** section in the sidebar of your xpander.ai dashboard. 2. Select **Github Issues Manager** with the same **connector name** you configured in the previous section (e.g., xpander-github-issues-manager). 3. Click **MCP Configuration**. 4. Enter the MCP configuration into the appropriate settings of the client app you want to use (e.g., Cursor, Windsurf, Claude Desktop, etc.). Img 5 ## AI Agent Github Issues Manager Prompt Library Below are possible prompts or use cases you can try after integrating Github Issues Manager into your xpander AI agent: ``` Can you create a new issue in {repo_owner}/{repo_name} about {issue_description}? ``` ``` Can you add the label {label_name} to issue {issue_number} in {repo_owner}/{repo_name}? ``` ``` Can you update the milestone {milestone_number} in {repo_owner}/{repo_name} with a new due date {due_date}? ``` ``` Can you list all issues assigned to me across my repositories? ``` ## Related Resources * [Understanding Model Context Protocol (MCP)](/guides/deploy/mcp) * [Github Issues Manager API Documentation](https://docs.github.com/en/rest/issues/) # Github Search Manager Source: https://docs.xpander.ai/connectors/github-search-manager Learn how to integrate AI agents with GitHub Search Manager using xpander.ai. Create intelligent workflows that dynamically query GitHub repositories, issues, and codebases based on contextual prompts. ## About Github Search Manager GitHub is a cloud-based platform designed for developers to store, manage, and collaborate on code. Key features of Github Search Manager include: * **Repositories**: Search for repositories based on criteria like name, description, topics, and more. * **Code**: Find specific code snippets or files within repositories. * **Commits**: Search commit messages and associated metadata. * **Issues and Pull Requests**: Locate issues or pull requests matching certain conditions. * **Users**: Search for users by username or other profile information. * **Topics**: Discover repositories associated with specific topics ## Authentication Options Below are possible authentication options you can choose: The simplest way to connect Github Search Manager is by using xpander.ai's built-in authentication: 1. Go to the **Connectors** section in the sidebar of your xpander.ai dashboard. 2. Select **Github Search Manager** from the available integrations. 3. Click **Sign in with Github Search Manager**. 4. Grant xpander.ai permission to access your Github workspace. 5. Your Github Search Manager integration is now ready to use. ### Generate a Github Search Manager API Key 1. Log in to your [Github account](https://github.com/). 2. Click on your profile icon in the top-right corner, then select **Settings**.\\ Img 1 3. In the sidebar, go to **Developer settings**. 4. Select **Personal access tokens**, then click on **Tokens (classic)**. 5. Click **Generate new token**, and then **Generate new token (classic)**.\\ Img 2 6. Add a description under the **Note** field, set an expiration date, and select the appropriate scopes for your token. 7. Click **Generate token**. You’ll see your Github access token—copy and store it securely. ### Integrate Github Search Manager into xpander.ai 1. Go to the **Connectors** section in the sidebar of your xpander.ai dashboard. 2. Select **Github Search Manager** from the available integrations. 3. Click **Other auth options**. 4. Enter a **connector name**, e.g., "xpander-github-search-manager". 5. Select **Integration User** as the authentication mode. 6. Select **API Key** as the authentication method. 7. Paste the Github access token into the provided field. 8. Choose **Bearer** as the **Auth Type**. 9. Save the configuration. Img 3 ## Integration of Github Search Manager into AI Agent Once you've configured your Github Search Manager account with the authentication option(s) described above, you can integrate it into your AI agent with xpander.ai: 1. In your xpander.ai dashboard, go to the **Agent Configuration** tab and select **Tools**, then click **Add Tools**. 2. Select **Connectors**. 3. Choose **Github Search Manager** with the same **conenctor name** you configured in the previous section (e.g., xpander-github-search-manager). 4. Select the available Github Search Manager operations that suit your use case. Img 4 ## Expose Github Search Manager as MCP Server Alternatively, you can also expose your Github Search Manager account as an MCP server. To do so: 1. Go to the **Connectors** section in the sidebar of your xpander.ai dashboard. 2. Select **Github Search Manager** with the same **connector name** you configured in the previous section (e.g., xpander-github-search-manager). 3. Click **MCP Configuration**. 4. Enter the MCP configuration into the appropriate settings of the client app you want to use (e.g., Cursor, Windsurf, Claude Desktop, etc.). Img 5 ## AI Agent Github Search Manager Prompt Library Below are possible prompts or use cases you can try after integrating Github Search Manager into your xpander AI agent: ``` Can you show me code snippets that implement a {specific_algorithm} in {language}? ``` ``` Are there any recent commits mentioning {bug_id} or fixing related issues? ``` ``` What are the most popular repositories related to {technology} or {framework}? ``` ``` Can you find all pull requests related to {feature_name} in {repo_name}? ``` ## Related Resources * [Understanding Model Context Protocol (MCP)](/guides/deploy/mcp) * [Github Search Manager API Documentation](https://docs.github.com/en/rest/search/search?apiVersion=2022-11-28) # Gitlab Source: https://docs.xpander.ai/connectors/gitlab Learn how to integrate AI agents with GitLab using xpander.ai. Create automated workflows that enhance your CI/CD pipelines, streamline code reviews, and boost project management efficiency. ## About GitLab GitLab is a comprehensive, open-core DevSecOps platform that enables software development, security, and operations teams to collaborate throughout the entire software development lifecycle. It integrates a wide range of tools into a single application, including Git repository management, issue tracking, continuous integration and delivery (CI/CD), security scanning, and monitoring. Key features include: * **Version Control**: Built on Git, GitLab offers robust version control capabilities, allowing teams to manage and track code changes effectively. * **CI/CD Pipelines**: Automate the process of building, testing, and deploying code, ensuring faster and more reliable software delivery. * **Security and Compliance**: Integrated security features, such as automated vulnerability scanning and compliance tracking, help identify and mitigate risks early in the development process. * **Collaboration Tools**: Features like issue boards, wikis, and snippets facilitate team collaboration and knowledge sharing. * **AI Integration**: Gitlab's recent versions have introduced AI-powered features, including code suggestions and contextual assistance within the integrated development environment (IDE), to enhance developer productivity. ## Authentication Options Below are possible authentication options you can choose: ### Generate a Gitlab API Key 1. Log in into your [Gitlab account](https://gitlab.com/). 2. On the top left of your sidebar, click on your profile account, and then select **Edit profile** Img 1 3. Navigate to **Access token** in the sidebar, and then click on **Add new token** Img 2 4. Give your access token a name, expiration date, and the necessary scopes. Then, click on **Create personal access token** 5. You'll see your Gitlab access token afterwards. ### Integrate Gitlab into xpander.ai 1. Go to the **Connectors** section in the sidebar of your xpander.ai dashboard. 2. Select **Gitlab** from the available integrations. 3. Click **Enable**. 4. Enter a **connector name**, e.g., "xpander-gitlab". 5. Select **Integration User** as the authentication mode. 6. Select **API Key** as the authentication method. 7. Paste the Gitlab access token the provided field. 8. Choose **Bearer** as the **Auth Type**. 9. Save the configuration. Img 3 ## Integration of GitLab into AI Agent Once you've configured your GitLab account with the authentication option(s) described above, you can integrate it into your AI agent with xpander.ai: 1. In your xpander.ai dashboard, go to the **Agent Configuration** tab and select **Tools**, then click **Add Tools**. 2. Select **Connectors**. 3. Choose **GitLab** with the same **connector name** you configured in the previous section (e.g., xpander-gitlab). 4. Select the available GitLab operations that suit your use case. Img 5 ## Expose GitLab as MCP Server Alternatively, you can also expose your GitLab account as an MCP server. To do so: 1. Go to the **Connectors** section in the sidebar of your xpander.ai dashboard. 2. Select **GitLab** with the same **connector name** you configured in the previous section (e.g., xpander-gitlab). 3. Click **MCP Configuration**. 4. Enter the MCP configuration into the appropriate settings of the client app you want to use (e.g., Cursor, Windsurf, Claude Desktop, etc.). Img 5 ## AI Agent GitLab Prompt Library Below are possible prompts or use cases you can try after integrating GitLab into your xpander AI agent: ``` Can you fetch the latest 5 commits for the project {project_id}? ``` ``` Can you show me all open merge requests for {project_id}? ``` ``` Can you fork the project {project_id} into my namespace {namespace_id}? ``` ``` Can I get the list of all issues assigned to {user_id} in the project {project_id}? ``` ## Related Resources * [Understanding Model Context Protocol (MCP)](/guides/deploy/mcp) * [GitLab API Documentation](https://docs.gitlab.com/api/rest/) # Google Analytics Source: https://docs.xpander.ai/connectors/google-analytics Learn how to integrate AI agents with Google Analytics using xpander.ai. Create intelligent, data-aware agents that can autonomously analyze, interpret, and act on your website's traffic and user behavior data. ## About Google Analytics Google Analytics is a free web analytics service offered by Google that tracks and reports website traffic and user behavior. It provides insights into how visitors interact with your website or app, helping you understand the effectiveness of your online presence and marketing strategies. Key features include: * **Audience Analysis**: Understand who your visitors are, including demographics, geographic locations, and devices used. * **Acquisition Insights**: Learn how users find your site—whether through search engines, social media, direct visits, or referral links. * **Behavior Tracking**: Monitor user interactions on your site, such as which pages they visit, how long they stay, and their navigation paths. * **Conversion Tracking**: Set up goals to track specific actions like purchases, sign-ups, or downloads, helping you measure the effectiveness of your site in achieving business objectives. * **Integration with Other Tools**: Google Analytics can be integrated with other Google services like Google Ads and Search Console, providing a more comprehensive view of your online performance. ## Authentication Options Below are possible authentication options you can choose: The simplest way to connect Google Analytics is by using xpander.ai's built-in authentication: 1. Go to the **Connectors** section in the sidebar of your xpander.ai dashboard. 2. Select **Google Analytics** from the available integrations. 3. Click **Sign in with Google Analytics**. 4. Grant xpander.ai permission to access your account. 5. Your Google Analytics integration is now ready to use. ## Integration of Google Analytics into AI Agent Once you've configured your Google Analytics account with the authentication option(s) described above, you can integrate it into your AI agent with xpander.ai: 1. In your xpander.ai dashboard, go to the **Agent Configuration** tab and select **Tools**, then click **Add Tools**. 2. Select **Connectors**. 3. Choose **Google Analytics** with the same **conenctor name** you configured in the previous section (e.g., xpander-google-analytics). 4. Select the available Google Analytics operations that suit your use case. Img 1 ## Expose Google Analytics as MCP Server Alternatively, you can also expose your Google Analytics account as an MCP server. To do so: 1. Go to the **Connectors** section in the sidebar of your xpander.ai dashboard. 2. Select **Google Analytics** with the same **connector name** you configured in the previous section (e.g., xpander-google-analytics). 3. Click **MCP Configuration**. 4. Enter the MCP configuration into the appropriate settings of the client app you want to use (e.g., Cursor, Windsurf, Claude Desktop, etc.). Img 2 ## AI Agent Google Analytics Prompt Library Below are possible prompts or use cases you can try after integrating Google Analytics into your xpander AI agent: ``` How do our multi-channel funnels perform from {start_date} to {end_date}? ``` ``` Can you create a new conversion goal to track when users {complete_action} on our website? ``` ``` Could you link our Google Analytics property to our Google Ads account with ID {customer_id}? ``` ``` Can you show me the real-time analytics for our website right now? ``` ## Related Resources * [Understanding Model Context Protocol (MCP)](/guides/deploy/mcp) * [Google Analytics API Documentation](https://developers.google.com/analytics/devguides/reporting/data/v1) # Google BigQuery Source: https://docs.xpander.ai/connectors/google-bigquery Learn how to integrate AI agents with Google BigQuery using xpander.ai. Create intelligent workflows that automatically query, analyze, and act on large-scale datasets. ## About Google BigQuery Google BigQuery is a fully managed, serverless data warehouse and analytics platform offered by Google Cloud. Key features include: * **Serverless Architecture**: BigQuery eliminates the need for infrastructure management, allowing users to focus solely on data analysis. * **Scalability**: It can process petabytes of data quickly, making it suitable for large-scale analytics. * **Built-in Machine Learning**: With BigQuery ML, users can create and execute machine learning models directly within BigQuery using SQL, facilitating predictive analytics without extensive ML expertise. * **Real-time Analytics**: BigQuery supports real-time data analysis, enabling timely insights for decision-making. * **Integration with Google Cloud Ecosystem**: It seamlessly integrates with other Google Cloud services, such as Cloud Storage, Dataflow, and Looker Studio, enhancing data processing and visualization capabilities. ## Authentication Options Below are possible authentication options you can choose: The simplest way to connect to Google BigQuery is by using xpander.ai's built-in authentication: 1. Go to the **Connectors** section in the sidebar of your xpander.ai dashboard. 2. Select **BigQuery** from the available integrations. 3. Click **Sign in with BigQuery**. 4. Grant xpander.ai permission to access your account. 5. Your Google BigQuery integration is now ready to use. ### Generate a Google BigQuery API Token 1. You’ll need access to the Google Cloud CLI tool to obtain your token. If it’s already installed, skip to step 5. 2. Download the Google Cloud CLI tool. 3. In the directory where you downloaded and extracted the SDK, run the installation script: ``` ./google-cloud-sdk/install.sh ``` 4. After installation, add the SDK’s `bin` directory to your `$PATH`: ``` export PATH="$PATH:$HOME/Downloads/google-cloud-sdk/bin" ``` 5. Initialize the gcloud CLI: ``` ./google-cloud-sdk/bin/gcloud init ``` 6. Run the following command and copy the token it generates: ``` gcloud auth print-access-token ``` ### Integrate Google BigQuery into xpander.ai 1. Go to the **Connectors** section in the sidebar of your xpander.ai dashboard. 2. Select **BigQuery** from the available integrations. 3. Click **Other auth options**. 4. Enter a **connector name**, e.g., "xpander-bigquery". 5. Select **Integration User** as the authentication mode. 6. Select **API Key** as the authentication method. 7. Paste the Google BigQuery access token into the provided field. 8. Choose **Bearer** as the **Auth Type**. 9. Save the configuration.\\ Img 1 ## Integration of Google BigQuery into AI Agent Once you've configured your Google BigQuery account with the authentication option(s) described above, you can integrate it into your AI agent with xpander.ai: 1. In your xpander.ai dashboard, go to the **Agent Configuration** tab and select **Tools**, then click **Add Tools**. 2. Select **Connectors**. 3. Choose **BigQuery** with the same **connector name** you configured in the previous section (e.g., xpander-bigquery). 4. Select the available Google BigQuery operations that suit your use case. Img 2 ## Expose Google BigQuery as MCP Server Alternatively, you can also expose your Google BigQuery account as an MCP server. To do so: 1. Go to the **Connectors** section in the sidebar of your xpander.ai dashboard. 2. Select **BigQuery** with the same **connector name** you configured in the previous section (e.g., xpander-bigquery). 3. Click **MCP Configuration**. 4. Enter the MCP configuration into the appropriate settings of the client app you want to use (e.g., Cursor, Windsurf, Claude Desktop, etc.). Img 3 ## AI Agent Google BigQuery Prompt Library Below are possible prompts or use cases you can try after integrating Google BigQuery into your xpander AI agent: ``` Could you show me all datasets within the {project_name} project? ``` ``` Can you create a new dataset called {dataset_name} in our {project_name} project with a 30-day expiration policy? ``` ``` I need detailed information about the {dataset_name} dataset in our {project_name} project. Can you retrieve that? ``` ``` Can you run this SQL query "{query_string}" on our {project_name} project using the {dataset_name}? ``` ## Related Resources * [Understanding Model Context Protocol (MCP)](/guides/deploy/mcp) * [BigQuery API Documentation](https://cloud.google.com/bigquery/docs/reference/rest) # Google Calendar Source: https://docs.xpander.ai/connectors/google-calendar Learn how to integrate AI agents with Google Calendar using xpander.ai. Create intelligent workflows that automatically schedule meetings, manage availability, send reminders, and adjust events in real-time based on contextual data. ## About Google Calendar Google Calendar is a free, cloud-based time-management and scheduling service developed by Google. Key features include: * **Event Creation & Management**: Schedule one-time or recurring events, set start and end times, add locations, and invite guests. You can also set reminders via email or push notifications. * **Multiple Calendar Support**: Create and manage multiple calendars within your account to separate work, personal, or project-specific events. Each calendar can be color-coded for easy identification. * **Sharing & Collaboration**: Share your calendar with others, allowing them to view or edit events. This is particularly useful for coordinating schedules within teams or families. * **Integration with Google Services**: Events from Gmail (like flight or hotel reservations) are automatically added to your calendar. It also integrates with Google Meet for video conferencing. * **Cross-Platform Accessibility**: Accessible via web browsers and dedicated apps for Android and iOS, ensuring your schedule is always at your fingertips. * **Customizable Views**: Switch between daily, weekly, monthly, or agenda views to suit your planning needs. ## Authentication Options Below are possible authentication options you can choose: The simplest way to connect Google Calendar is by using xpander.ai's built-in authentication: 1. Go to the **Connectors** section in the sidebar of your xpander.ai dashboard. 2. Select **Google Calendar** from the available integrations. 3. Click **Sign in with Google Calendar**. 4. Grant xpander.ai permission to access your account. 5. Your Google Calendar integration is now ready to use. This method is recommended for most users. xpander.ai securely manages your OAuth tokens without exposing any credentials. ### Generate a Google Calendar API Key 1. Log in to your [Google Cloud Console](https://console.cloud.google.com/). 2. Create a new project or select an existing one.\\ Img 1 3. Go to the [Google Cloud API Library](https://console.cloud.google.com/apis/library).\\ Img 2 4. Search for and select **Google Calendar API**, then click **Enable**. 5. In the sidebar, go to **Credentials**. 6. Click **Create credentials**, and select **API key**.\\ Img 3 7. Restrict the API key to Google Calendar API only (optional but recommended).\\ Img 4 ### Integrate Google Calendar into xpander.ai 1. Go to the **Connectors** section in the sidebar of your xpander.ai dashboard. 2. Select **Google Calendar** from the available integrations. 3. Click **Other auth options**. 4. Enter a **connector name**, e.g., "xpander-google-calendar". 5. Select **Integration User** as the authentication mode. 6. Select **API Key** as the authentication method. 7. Paste the Google Calendar API key into the provided field. 8. Choose **Basic** as the **Auth Type**. 9. Save the configuration.\\ Img 5 API keys provide limited functionality and are best for read-only operations on public files. For full access, use OAuth methods. ## Integration of Google Calendar into AI Agent Once you've configured your Google Calendar account with the authentication option(s) described above, you can integrate it into your AI agent with xpander.ai: 1. In your xpander.ai dashboard, go to the **Agent Configuration** tab and select **Tools**, then click **Add Tools**. 2. Select **Connectors**. 3. Choose **Google Calendar** with the same **connector name** you configured in the previous section (e.g., xpander-google-calendar). 4. Select the available Google Calendar operations that suit your use case. Img 6 ## Expose Google Calendar as MCP Server Alternatively, you can also expose your Google Calendar account as an MCP server. To do so: 1. Go to the **Connectors** section in the sidebar of your xpander.ai dashboard. 2. Select **Google Calendar** with the same **connector name** you configured in the previous section (e.g., xpander-google-calendar). 3. Click **MCP Configuration**. 4. Enter the MCP configuration into the appropriate settings of the client app you want to use (e.g., Cursor, Windsurf, Claude Desktop, etc.). Img 7 ## AI Agent Google Calendar Prompt Library Below are possible prompts or use cases you can try after integrating Google Calendar into your xpander AI agent: ``` Could you create a new dashboard for monitoring {application_name} performance metrics? ``` ``` Can you set up a monitor to alert us when {service_name} latency exceeds {threshold_value} milliseconds? ``` ``` Could you temporarily mute alerts for {host_name} during our scheduled maintenance window on {date}? ``` ``` Could you integrate our AWS {account_name} account to monitor our EC2 and Lambda resources? ``` ## Related Resources * [Understanding Model Context Protocol (MCP)](/guides/deploy/mcp) * [Google Calendar API Documentation](https://developers.google.com/workspace/calendar/api/guides/overview) # Google Cloud Monitoring Source: https://docs.xpander.ai/connectors/google-cloud-monitoring Learn how to integrate AI agents with Google Cloud Monitoring using xpander.ai. Create intelligent AI agents that can automatically track metrics, respond to alerts, and take action on real-time performance and system health insights across your cloud infrastructure. ## About Google Cloud Monitoring **Google Cloud Monitoring** is a fully managed observability and monitoring platform offered by Google Cloud. Key features include: * **Comprehensive Metrics Collection**: Collects metrics from Google Cloud services, virtual machines, containers, databases, and custom applications to provide deep visibility into system performance and health. * **Real-Time Alerting**: Create and manage alerting policies based on metrics, thresholds, and logs to detect and respond to incidents proactively. * **Uptime Monitoring**: Monitor the availability and responsiveness of applications and endpoints from multiple global locations. * **Integration with Google Cloud Ecosystem**: Seamlessly integrates with services like Cloud Logging, Cloud Trace, Kubernetes Engine (GKE), and other GCP tools to provide a unified observability experience across your cloud environment. ## Authentication Options Below are possible authentication options you can choose: The simplest way to connect Google Cloud Monitoring is by using xpander.ai's built-in authentication: 1. Go to the **Connectors** section in the sidebar of your xpander.ai dashboard. 2. Select **Google Cloud Monitoring** from the available integrations. 3. Click **+ Create new connection**. 4. Enter a **connector name** as desired, e.g., "xpander-cloud-monitoring". 5. Choose **OAuth2** as the authentication method. 6. Click **Sign in with Google Cloud Monitoring**. 7. Grant xpander.ai permission to access your account. 8. Save the configuration. Img 1 ### Generate a Google Cloud Monitoring API Token 1. You’ll need access to the Google Cloud CLI tool to obtain your token. If it’s already installed, skip to step 5. 2. Download the Google Cloud CLI tool. 3. In the directory where you downloaded and extracted the SDK, run the installation script: ``` ./google-cloud-sdk/install.sh ``` 4. After installation, add the SDK’s `bin` directory to your `$PATH`: ``` export PATH="$PATH:$HOME/Downloads/google-cloud-sdk/bin" ``` 5. Initialize the gcloud CLI: ``` ./google-cloud-sdk/bin/gcloud init ``` 6. Run the following command and copy the token it generates: ``` gcloud auth print-access-token ``` ### Integrate Google Cloud Monitoring into xpander.ai 1. Go to the **Connectors** section in the sidebar of your xpander.ai dashboard. 2. Select **Google Cloud Monitoring** from the available integrations. 3. Click **+ Create new connection**. 4. Enter a **connector name** as desired, e.g., "xpander-cloud-monitoring". 5. Choose **API Key** as the authentication method. 6. Paste your Google Cloud Monitoring access token into the provided field. 7. Choose **Bearer** as the **Auth Type**. 8. Save the configuration. Img 2 ## Integration of Google Cloud Monitoring into an AI Agent Once you’ve configured your Google Cloud Monitoring connector with the authentication option described above, you can integrate it into your AI agent with xpander.ai: 1. In your xpander.ai dashboard, navigate to the **Agents** page, then click an agent to open the **Agent Configuration** tab. 2. Select **Tools**, then click **Add Tools**. 3. Select **Connectors**. 4. Choose **Google Cloud Monitoring** with the same **connector name** you configured in the previous section (e.g., xpander-cloud-monitoring). 5. Select the available Google Cloud Monitoring operations that suit your use case. To grant your agent cloud monitoring capabilities, enable the following operations. * **List Project Alerts** * **Get Alert** * **List Folder Time Series** * **Get Alert Policy** * **List Metric Descriptor** * **List Project Alert Snoozes** 6. Click **Deploy** to update your agent. Img 3 ## AI Agent Google Cloud Monitoring Prompt Library Below are possible prompts or use cases you can try after integrating Google Cloud Monitoring into your xpander.ai AI agent: ``` List all active alerting policies in my Google Cloud project. ``` ``` Show me the CPU utilization metrics for my Compute Engine instances in the last 24 hours. ``` ``` Show uptime check results for over the past 7 days. ``` ``` Get memory usage metrics for for the last 1 hour. ``` Gif 1 ## Related Resources * [Using Tools & Connectors in the xpander.ai platform](/guides/agents/tools-connectors) * [Google Cloud Monitoring Documentation](https://docs.cloud.google.com/monitoring/docs) # Google Docs Source: https://docs.xpander.ai/connectors/google-docs Learn how to integrate AI agents with Google Docs using xpander.ai. Create intelligent workflows that automatically analyze, summarize, and generate content within your documents. ## About Google Docs Google Docs is a free, web-based word processor developed by Google, allowing users to create, edit, and collaborate on documents in real-time. Key features include: * **Real-Time Collaboration**: Multiple users can work on a document simultaneously, with changes reflected instantly. * **Cloud-Based Access**: Documents are stored in Google Drive, ensuring access from any device with internet connectivity. * **Version History**: Track and revert to previous versions of a document. * **Offline Editing**: With the Google Docs Offline extension, users can edit documents without an internet connection. * **Compatibility**: Supports various file formats, including Microsoft Word (.docx), and allows exporting to formats like PDF. ## Authentication Options Below are possible authentication options you can choose: The simplest way to connect Google Docs is by using xpander.ai's built-in authentication: 1. Go to the **Connectors** section in the sidebar of your xpander.ai dashboard. 2. Select **Google Docs** from the available integrations. 3. Click **Sign in with Google Docs**. 4. Grant xpander.ai permission to access your account. 5. Your Google Docs integration is now ready to use. This method is recommended for most users. xpander.ai securely manages your OAuth tokens without exposing any credentials. ### Generate a Google Docs API Key 1. Log in to your [Google Cloud Console](https://console.cloud.google.com/). 2. Create a new project or select an existing one.\\ Img 1 3. Go to the [Google Cloud API Library](https://console.cloud.google.com/apis/library).\\ Img 2 4. Search for and select **Google Docs API**, then click **Enable**. 5. In the sidebar, go to **Credentials**. 6. Click **Create credentials**, and select **API key**.\\ Img 3 7. Restrict the API key to Google Docs API only (optional but recommended).\\ Img 4 ### Integrate Google Docs into xpander.ai 1. Go to the **Connectors** section in the sidebar of your xpander.ai dashboard. 2. Select **Google Docs** from the available integrations. 3. Click **Other auth options**. 4. Enter a **connector name**, e.g., "xpander-google-docs". 5. Select **Integration User** as the authentication mode. 6. Select **API Key** as the authentication method. 7. Paste the Google Docs API key into the provided field. 8. Choose **Basic** as the **Auth Type**. 9. Save the configuration.\\ Img 5 API keys provide limited functionality and are best for read-only operations on public files. For full access, use OAuth methods. ## Integration of Google Docs into AI Agent Once you've configured your Google Docs account with the authentication option(s) described above, you can integrate it into your AI agent with xpander.ai: 1. In your xpander.ai dashboard, go to the **Agent Configuration** tab and select **Tools**, then click **Add Tools**. 2. Select **Connectors**. 3. Choose **Google Docs** with the same **connector name** you configured in the previous section (e.g., xpander-google-docs). 4. Select the available Google Docs operations that suit your use case. Img 6 ## Expose Google Docs as MCP Server Alternatively, you can also expose your Google Docs account as an MCP server. To do so: 1. Go to the **Connectors** section in the sidebar of your xpander.ai dashboard. 2. Select **Google Docs** with the same **connector name** you configured in the previous section (e.g., xpander-google-docs). 3. Click **MCP Configuration**. 4. Enter the MCP configuration into the appropriate settings of the client app you want to use (e.g., Cursor, Windsurf, Claude Desktop, etc.). Img 7 ## AI Agent Google Docs Prompt Library Below are possible prompts or use cases you can try after integrating Google Docs into your xpander AI agent: ``` Can you create a new document titled {document_title} for our {project_name} project? ``` ``` Can you update the text style in document {document_name} to {style_type} for {section_name}? ``` ``` Can you update the section formatting in document {document_name} for {chapter_name}? ``` ``` Can you create a new document for {meeting_date} and apply {font_style} to its text? ``` ## Related Resources * [Understanding Model Context Protocol (MCP)](/guides/deploy/mcp) * [Google Docs API Documentation](https://developers.google.com/workspace/docs/api/reference/rest) # Google Drive Source: https://docs.xpander.ai/connectors/google-drive Learn how to build AI agents with Google Drive access using xpander.ai. Create intelligent document-aware AI assistants that can read, write, organize, and analyze files automatically. Learn how to build AI agents with Google Drive access using xpander.ai. This integration enables intelligent document-aware AI assistants that can read, write, organize, and analyze files automatically. ## Authentication Options Choose the authentication method that best fits your needs: The simplest way to connect Google Drive is using xpander.ai's built-in authentication: 1. Go to the **Connectors** section in xpander.ai dashboard 2. Select **Google Drive** from available integrations 3. Click **Sign in with Google** 4. Select your Google account and grant permissions 5. Your connection is immediately active and ready to use This method is recommended for most users. xpander.ai securely manages your OAuth tokens without exposing any credentials. For programmatic access and automation: 1. Go to [Google Cloud Console](https://console.cloud.google.com/) 2. Create a new project or select an existing one 3. Enable the **Google Drive API** in Library 4. Go to **Credentials** and create an **API Key** 5. Restrict the API key to Google Drive API only 6. Copy the API key to xpander.ai's Google Drive connection settings 7. Set appropriate API access restrictions in Google Cloud Console API keys provide limited functionality and are best for read-only operations on public files. For full access, use OAuth methods. For advanced customization and enterprise setups: ### Step 1: Create OAuth Credentials 1. Log into [Google Cloud Console](https://console.cloud.google.com/) 2. Create a new project or select existing one 3. Enable the **Google Drive API** in Library 4. Configure **OAuth consent screen** with appropriate scopes: * `/auth/drive.file` (recommended) * `/auth/drive` (full access) * `/auth/drive.readonly` (read-only) 5. Create **OAuth 2.0 credentials** (Client ID & Secret) 6. Add `https://platform.xpander.ai/oauth/callback` as redirect URI ### Step 2: Configure in xpander.ai 1. Go to **Connectors** section in xpander.ai dashboard 2. Select **Google Drive** and choose **Manual Configuration** 3. Enter your **Client ID** and **Client Secret** 4. Specify the required scopes 5. Click **Authorize** and complete the OAuth flow 6. Verify connection is active Manual configuration gives you precise control over permissions and is recommended for enterprise deployments or specific security requirements. For organization-wide access or automated workflows without user intervention: ### Step 1: Create a Service Account 1. Log into [Google Cloud Console](https://console.cloud.google.com/) 2. Navigate to your project → **IAM & Admin** → **Service Accounts** 3. Click **Create Service Account** 4. Give it a name and description 5. Assign appropriate roles (e.g., "Drive File Creator") 6. Create and download a JSON key file ### Step 2: Configure in xpander.ai 1. Go to **Connectors** section in xpander.ai dashboard 2. Select **Google Drive** and choose **Service Account** 3. Upload the JSON key file 4. Verify the connection status ### Step 3: Share Resources * Share specific Google Drive folders/files with the service account's email address * The email usually follows this format: `service-account-name@project-id.iam.gserviceaccount.com` Service accounts act as separate Google identities and are ideal for background processes, automation, and accessing shared organizational resources without user intervention. ## Model Context Protocol (MCP) for Google Drive Integration xpander.ai's Model Context Protocol (MCP) is the proprietary technology that powers AI agent interactions with Google Drive. Unlike basic integrations, MCP provides: * **Secure credential handling** - OAuth tokens are managed securely without exposing keys * **Enhanced context awareness** - AI agents maintain context across file operations * **Document state management** - Track changes and updates across sessions * **Structured data exchange** - Standardized format for AI-to-Drive communication * **Intelligent operation routing** - Automatic selection of appropriate Drive API endpoints This protocol enables your AI agents to interact with Google Drive in a more natural, secure, and efficient way than standard API integrations. ## AI Agent Google Drive Prompt Library ### Document Creation Prompts Use these prompts to have your AI agent create Google Drive documents: ``` Create a new Google Doc titled "{title}" with the following sections: - Executive Summary - Project Scope - Timeline - Budget - Team Responsibilities ``` ``` Generate a weekly report for {project} based on the data in the "{spreadsheet}" file. Include progress metrics, blockers, and next steps. ``` ``` Draft an email to the team about {topic} and save it as a Google Doc. Include key points from our last meeting on {date}. ``` ### Document Analysis Prompts These prompts help your AI agent extract insights from Google Drive documents: ``` Analyze the document "{document_name}" and extract the main points about {topic}. Provide a 3-paragraph summary. ``` ``` Read through all documents in the folder "{folder_name}" and identify common themes related to {keyword}. Create a summary document. ``` ``` Compare the two presentations "{doc1}" and "{doc2}" and highlight the key differences in approach and content. ``` ### File Management Prompts Enable your AI agent to organize and manage Google Drive files with these prompts: ``` Find all files related to {project_name} created in the last {time_period} and organize them into folders by document type. ``` ``` Create a folder structure for project {project_name} with the following subfolders: Documentation, Assets, Planning, and Reports. ``` ``` Search my Drive for files containing information about {topic} and share them with {email_address} with view-only permissions. ``` ## Google Drive AI Integration Troubleshooting ### Common Authentication Issues * Verify Client ID and Secret are entered correctly in xpander.ai * Ensure the complete OAuth flow was successfully completed * Check that redirect URIs match exactly between Google Cloud and xpander.ai * Confirm Google Drive API is enabled in Google Cloud Console for your project ## Related Resources * [Understanding Model Context Protocol (MCP)](/guides/deploy/mcp) * [Google Drive API Documentation](https://developers.google.com/drive/api/v3/about-sdk) # Google Forms Source: https://docs.xpander.ai/connectors/google-forms Learn how to integrate AI agents with Google Forms using xpander.ai. Create dynamic, intelligent forms that can automatically analyze responses, provide personalized follow-ups, and streamline data collection. ## About Google Forms Google Forms is a free, web-based application developed by Google that allows users to create and manage surveys, quizzes, and various types of online forms. Key features include: * **Question Types**: Google Forms offers a variety of question formats, including multiple-choice, short answer, checkboxes, dropdowns, linear scales, file uploads, and more. * **Conditional Logic**: You can set up forms to show or hide questions based on previous answers, allowing for dynamic and personalized surveys. * **Templates**: The platform provides a range of pre-designed templates for different purposes, such as event registrations, feedback surveys, and quizzes. * **Customization**: Customize the look of your forms by adding images, videos, and adjusting the theme colors and fonts. * **Real-Time Collaboration**: Multiple users can collaborate on the same form simultaneously, making it ideal for team projects. * **Data Analysis**: Responses are automatically collected and can be viewed in summary charts or exported to Google Sheets for detailed analysis. ## Authentication Options Below are possible authentication options you can choose: ### Generate a Google Forms API Key 1. Log in to your [Google Cloud Console](https://console.cloud.google.com/). 2. Create a new project or select an existing one.\\ Img 1 3. Go to the [Google Cloud API Library](https://console.cloud.google.com/apis/library).\\ Img 2 4. Search for and select **Google Forms API**, then click **Enable**. 5. In the sidebar, go to **Credentials**. 6. Click **Create credentials**, and select **API key**.\\ Img 3 7. Restrict the API key to Google Forms API only (optional but recommended).\\ Img 4 ### Integrate Google Forms into xpander.ai 1. Go to the **Connectors** section in the sidebar of your xpander.ai dashboard. 2. Select **Google Forms** from the available integrations. 3. Click **Enable**. 4. Enter a **connector name**, e.g., "xpander-google-forms". 5. Select **Integration User** as the authentication mode. 6. Select **API Key** as the authentication method. 7. Paste the Google Forms API key into the provided field. 8. Choose **Basic** as the **Auth Type**. 9. Save the configuration.\\ Img 5 ## Integration of Google Forms into AI Agent Once you've configured your Google Forms account with the authentication option(s) described above, you can integrate it into your AI agent with xpander.ai: 1. In your xpander.ai dashboard, go to the **Agent Configuration** tab and select **Tools**, then click **Add Tools**. 2. Select **Connectors**. 3. Choose **Google Forms** with the same **connector name** you configured in the previous section (e.g., xpander-google-forms). 4. Select the available Google Forms operations that suit your use case. Img 6 ## Expose Google Forms as MCP Server Alternatively, you can also expose your Google Forms account as an MCP server. To do so: 1. Go to the **Connectors** section in the sidebar of your xpander.ai dashboard. 2. Select **Google Forms** with the same **connector name** you configured in the previous section (e.g., xpander-google-forms). 3. Click **MCP Configuration**. 4. Enter the MCP configuration into the appropriate settings of the client app you want to use (e.g., Cursor, Windsurf, Claude Desktop, etc.). Img 7 ## AI Agent Google Forms Prompt Library Below are possible prompts or use cases you can try after integrating Google Forms into your xpander AI agent: ``` Can you create a new Google Form titled {form_title} for our upcoming event? ``` ``` Can you list all responses for the Google Form {form_name} for our data analysis? ``` ``` Can you list all notification watches for the Google Form {form_name} to ensure proper monitoring? ``` ``` Can you update the Google Form {form_name} to add a new question about {question_topic}? ``` ## Related Resources * [Understanding Model Context Protocol (MCP)](/guides/deploy/mcp) * [Google Forms API Documentation](https://developers.google.com/workspace/forms/api/reference/rest) # Google Gmail Source: https://docs.xpander.ai/connectors/google-gmail Learn how to integrate AI agents with Google Gmail using xpander.ai. Create automated workflows that streamline your email management, enhance productivity with smart replies, and personalize customer interactions by leveraging AI-driven insights. ## About Google Gmail Gmail is Google's free, web-based email service. Key features include: * **Free Storage**: Users receive 15 GB of free storage shared across Gmail, Google Drive, and Google Photos. Additional storage can be purchased through Google One . * **Integrated Google Services**: Gmail seamlessly integrates with other Google services like Google Drive, Calendar, Meet, and Chat, allowing users to manage emails, schedule events, and join video meetings without leaving the platform . * **Spam Filtering**: Gmail employs advanced spam filtering techniques to automatically detect and move suspicious emails to the Spam folder, reducing unwanted messages in the inbox . * **Conversation View**: Emails are grouped into threads, making it easier to follow conversations and reducing inbox clutter . * **Advanced Search Capabilities**: Gmail offers powerful search features, allowing users to find emails by sender, date, attachments, and more . ## Authentication Options Below are possible authentication options you can choose: The simplest way to connect Google Gmail is by using xpander.ai's built-in authentication: 1. Go to the **Connectors** section in the sidebar of your xpander.ai dashboard. 2. Select **Google SheeGmailts** from the available integrations. 3. Click **Sign in with Google Gmail**. 4. Grant xpander.ai permission to access your account. 5. Your Google Gmail integration is now ready to use. This method is recommended for most users. xpander.ai securely manages your OAuth tokens without exposing any credentials. ### Generate a Google Gmail API Key 1. Log in to your [Google Cloud Console](https://console.cloud.google.com/). 2. Create a new project or select an existing one.\\ Img 1 3. Go to the [Google Cloud API Library](https://console.cloud.google.com/apis/library).\\ Img 2 4. Search for and select **Google Gmail API**, then click **Enable**. 5. In the sidebar, go to **Credentials**. 6. Click **Create credentials**, and select **API key**.\\ Img 3 7. Restrict the API key to Google Gmaiil API only (optional but recommended).\\ Img 4 ### Integrate Google Gmail into xpander.ai 1. Go to the **Connectors** section in the sidebar of your xpander.ai dashboard. 2. Select **Google Gmail** from the available integrations. 3. Click **Other auth options**. 4. Enter a **connector name**, e.g., "xpander-google-gmail". 5. Select **Integration User** as the authentication mode. 6. Select **API Key** as the authentication method. 7. Paste the Google Gmail API key into the provided field. 8. Choose **Basic** as the **Auth Type**. 9. Save the configuration.\\ Img 5 API keys provide limited functionality and are best for read-only operations on public files. For full access, use OAuth methods. ## Integration of Google Gmail into AI Agent Once you've configured your Google Gmail account with the authentication option(s) described above, you can integrate it into your AI agent with xpander.ai: 1. In your xpander.ai dashboard, go to the **Agent Configuration** tab and select **Tools**, then click **Add Tools**. 2. Select **Connectors**. 3. Choose **Google Gmail** with the same **connector name** you configured in the previous section (e.g., xpander-google-gmail). 4. Select the available Google Gmail operations that suit your use case. Img 6 ## Expose Google Gmail as MCP Server Alternatively, you can also expose your Google Gmail account as an MCP server. To do so: 1. Go to the **Connectors** section in the sidebar of your xpander.ai dashboard. 2. Select **Google Gmail** with the same **connector name** you configured in the previous section (e.g., xpander-google-gmail). 3. Click **MCP Configuration**. 4. Enter the MCP configuration into the appropriate settings of the client app you want to use (e.g., Cursor, Windsurf, Claude Desktop, etc.). Img 7 ## AI Agent Google Gmail Prompt Library Below are possible prompts or use cases you can try after integrating Google Gmail into your xpander AI agent: ``` Can you create a new draft email for {user_email} with the subject {subject_line}? ``` ``` Can you retrieve the details of the email message from {user_email}? ``` ``` Can you enable push notifications for new emails from {user_email}? ``` ``` Can you send the draft email {draft_name} to {user_email}? ``` ## Related Resources * [Understanding Model Context Protocol (MCP)](/guides/deploy/mcp) * [Google Gmail API Documentation](https://developers.google.com/workspace/gmail/api/guides) # Google Sheets Source: https://docs.xpander.ai/connectors/google-sheets Learn how to integrate AI agents with Google Sheets using xpander.ai. Create intelligent workflows that automate data analysis, trigger actions based on cell values, and enable natural language interaction with your spreadsheets. ## About Google Sheets Google Sheets is a free, cloud-based spreadsheet application developed by Google. It enables users to create, edit, and collaborate on spreadsheets in real-time across various devices, including web browsers and mobile apps for Android and iOS. Key features include: * **Real-Time Collaboration**: Multiple users can work on the same spreadsheet simultaneously. * **Comprehensive Functionality**: supports a wide array of functions and formulas for data manipulation, including mathematical, statistical, logical, and text functions. Users can create pivot tables, apply conditional formatting, and use data validation to ensure data integrity . * **Data Visualization**: Users can generate various types of charts and graphs to visualize data effectively. The "Explore" feature leverages machine learning to provide insights, suggest charts, and answer questions about the data . * **Offline Access**: With offline mode enabled, users can continue working on their spreadsheets without an internet connection. Changes made offline are synchronized automatically once connectivity is restored . * **Integration and Compatibility**: Google Sheets is compatible with various file formats, including Microsoft Excel (.xls, .xlsx), CSV, and PDF. It also integrates with other Google services and supports add-ons to extend its functionality . * **Automation with Google Apps Script**: Users can automate tasks and create custom functions using Google Apps Script, a JavaScript-based language. This allows for the development of macros and integration with external APIs . ## Authentication Options Below are possible authentication options you can choose: The simplest way to connect Google Sheets is by using xpander.ai's built-in authentication: 1. Go to the **Connectors** section in the sidebar of your xpander.ai dashboard. 2. Select **Google Sheets** from the available integrations. 3. Click **Sign in with Google Sheets**. 4. Grant xpander.ai permission to access your account. 5. Your Google Sheets integration is now ready to use. This method is recommended for most users. xpander.ai securely manages your OAuth tokens without exposing any credentials. ### Generate a Google Sheets API Key 1. Log in to your [Google Cloud Console](https://console.cloud.google.com/). 2. Create a new project or select an existing one.\\ Img 1 3. Go to the [Google Cloud API Library](https://console.cloud.google.com/apis/library).\\ Img 2 4. Search for and select **Google Sheets API**, then click **Enable**. 5. In the sidebar, go to **Credentials**. 6. Click **Create credentials**, and select **API key**.\\ Img 3 7. Restrict the API key to Google Sheets API only (optional but recommended).\\ Img 4 ### Integrate Google Sheets into xpander.ai 1. Go to the **Connectors** section in the sidebar of your xpander.ai dashboard. 2. Select **Google Sheets** from the available integrations. 3. Click **Other auth options**. 4. Enter a **connector name**, e.g., "xpander-google-sheets". 5. Select **Integration User** as the authentication mode. 6. Select **API Key** as the authentication method. 7. Paste the Google Sheets API key into the provided field. 8. Choose **Basic** as the **Auth Type**. 9. Save the configuration. Img 5 API keys provide limited functionality and are best for read-only operations on public files. For full access, use OAuth methods. ## Integration of Google Sheets into AI Agent Once you've configured your Google Sheets account with the authentication option(s) described above, you can integrate it into your AI agent with xpander.ai: 1. In your xpander.ai dashboard, go to the **Agent Configuration** tab and select **Tools**, then click **Add Tools**. 2. Select **Connectors**. 3. Choose **Google Sheets** with the same **connector name** you configured in the previous section (e.g., xpander-google-sheets). 4. Select the available Google Sheets operations that suit your use case. Img 6 ## Expose Google Sheets as MCP Server Alternatively, you can also expose your Google Sheets account as an MCP server. To do so: 1. Go to the **Connectors** section in the sidebar of your xpander.ai dashboard. 2. Select **Google Sheets** with the same **connector name** you configured in the previous section (e.g., xpander-google-sheets). 3. Click **MCP Configuration**. 4. Enter the MCP configuration into the appropriate settings of the client app you want to use (e.g., Cursor, Windsurf, Claude Desktop, etc.). Img 7 ## AI Agent Google Sheets Prompt Library Below are possible prompts or use cases you can try after integrating Google Sheets into your xpander AI agent: ``` Can you create a new spreadsheet titled {my_title} with a data source schedule for {my_refresh_scope}? ``` ``` Can you retrieve the values in range {my_cell_range} from spreadsheet {my_spreadsheet}? ``` ``` Can you copy the sheet {my_sheet} from spreadsheet {my_source_spreadsheet} to {my_destination_spreadsheet}? ``` ``` Can you get the metadata {my_metadata} from spreadsheet {my_spreadsheet}? ``` ## Related Resources * [Understanding Model Context Protocol (MCP)](/guides/deploy/mcp) * [Google Sheets API Documentation](https://developers.google.com/workspace/sheets/api/guides/concepts) # Google Tasks Source: https://docs.xpander.ai/connectors/google-tasks Learn how to integrate AI agents with Google Tasks using xpander.ai. Create intelligent task workflows that automatically add, update, or complete tasks based on triggers from your apps, conversations, or calendar events. ## About Google Tasks Google Tasks is a free, minimalist task management tool developed by Google, designed to help users create and manage to-do lists across devices. Key features include: * **Task Creation & Organization**: Quickly add tasks with titles, optional descriptions, due dates, and subtasks. Tasks can be organized into multiple lists to manage different projects or categories. * **Due Dates & Reminders**: Assign due dates and times to tasks, which then appear in your Google Calendar. You can also set tasks to repeat on a regular schedule. * **Integration with Gmail & Calendar**: Convert emails into tasks directly from Gmail, and view tasks alongside events in Google Calendar. * **Cross-Device Sync**: Access and manage your tasks on the web or through the mobile app on Android and iOS devices, with all data syncing across platforms. * **Simple Interface**: Google Tasks offers a clean and user-friendly interface, making it easy to create, organize, and manage tasks. ## Authentication Options Below are possible authentication options you can choose: The simplest way to connect Google Tasks is by using xpander.ai's built-in authentication: 1. Go to the **Connectors** section in the sidebar of your xpander.ai dashboard. 2. Select **Google Tasks** from the available integrations. 3. Click **Sign in with Google Tasks**. 4. Grant xpander.ai permission to access your account. 5. Your Google Tasks integration is now ready to use. This method is recommended for most users. xpander.ai securely manages your OAuth tokens without exposing any credentials. ### Generate a Google Tasks API Key 1. Log in to your [Google Cloud Console](https://console.cloud.google.com/). 2. Create a new project or select an existing one.\\ Img 1 3. Go to the [Google Cloud API Library](https://console.cloud.google.com/apis/library).\\ Img 2 4. Search for and select **Google Tasks API**, then click **Enable**. 5. In the sidebar, go to **Credentials**. 6. Click **Create credentials**, and select **API key**.\\ Img 3 7. Restrict the API key to Google Tasks API only (optional but recommended).\\ Img 4 ### Integrate Google Tasks into xpander.ai 1. Go to the **Connectors** section in the sidebar of your xpander.ai dashboard. 2. Select **Google Tasks** from the available integrations. 3. Click **Other auth options**. 4. Enter a **connector name**, e.g., "xpander-google-tasks". 5. Select **Integration User** as the authentication mode. 6. Select **API Key** as the authentication method. 7. Paste the Google Tasks API key into the provided field. 8. Choose **Basic** as the **Auth Type**. 9. Save the configuration.\\ Img 5 API keys provide limited functionality and are best for read-only operations on public files. For full access, use OAuth methods. ## Integration of Google Tasks into AI Agent Once you've configured your Google Tasks account with the authentication option(s) described above, you can integrate it into your AI agent with xpander.ai: 1. In your xpander.ai dashboard, go to the **Agent Configuration** tab and select **Tools**, then click **Add Tools**. 2. Select **Connectors**. 3. Choose **Google Tasks** with the same **connector name** you configured in the previous section (e.g., xpander-google-tasks). 4. Select the available Google Tasks operations that suit your use case. Img 6 ## Expose Google Tasks as MCP Server Alternatively, you can also expose your Google Tasks account as an MCP server. To do so: 1. Go to the **Connectors** section in the sidebar of your xpander.ai dashboard. 2. Select **Google Tasks** with the same **connector name** you configured in the previous section (e.g., xpander-google-tasks). 3. Click **MCP Configuration**. 4. Enter the MCP configuration into the appropriate settings of the client app you want to use (e.g., Cursor, Windsurf, Claude Desktop, etc.). Img 7 ## AI Agent Google Tasks Prompt Library Below are possible prompts or use cases you can try after integrating Google Tasks into your xpander AI agent: ``` Can you clear all completed tasks from my task list {list_name}? ``` ``` Can you show me all tasks in my project list {project_name}? ``` ``` Can you give me details about the task {task_name} in my list {list_name}? ``` ``` Can you update the task {task_name} in my list {list_name} with a new due date {due_date}? ``` ## Related Resources * [Understanding Model Context Protocol (MCP)](/guides/deploy/mcp) * [Google Tasks API Documentation](http://developers.google.com/workspace/tasks/reference/rest) # HubSpot Blogs Source: https://docs.xpander.ai/connectors/hubspot-blogs Learn how to integrate AI agents with HubSpot Blogs using xpander.ai. Create intelligent, automated content workflows that personalize blog posts, optimize SEO in real-time, and schedule publishing based on audience engagement trends. ## About HubSpot Blogs HubSpot Blogs refer to two interconnected offerings from HubSpot: * **HubSpot's Official Blog**: This is a content-rich platform where HubSpot publishes articles on marketing, sales, customer service, and business growth. It serves as a resource for professionals seeking insights and strategies in these domains. * **HubSpot's Blogging Tool**: This is a feature within HubSpot's Content Management System (CMS) that allows users to create, manage, and optimize their own blogs. It's designed to help businesses attract and engage audiences through content marketing. ## Authentication Options Below are possible authentication options you can choose: The simplest way to connect HubSpot Blogs is by using xpander.ai's built-in authentication: 1. Go to the **Connectors** section in the sidebar of your xpander.ai dashboard. 2. Select **HubSpot Blogs** from the available integrations. 3. Click **Sign in with HubSpot Blogs**. 4. Choose the account you want to connect and grant xpander.ai permission to access it. 5. HubSpot Blogs is now ready to use. ### Generate a HubSpot Blogs API Key 1. Log in to your [HubSpot Blogs account](https://www.hubspot.com/products/content/blog). 2. Click on **Settings** (the gear icon) in the top bar of your dashboard. 3. In the sidebar, click on **Integration**. 4. Choose **Private Apps**, then click **Create Private App**.\\ Img 1 5. Give your app a name, then go to the **Scopes** tab and click **Add new scope**. 6. Under the **Other** section, check the box for `content`.\\ Img 2 7. Click **Create App**. 8. Your access token will be available in the **Auth** tab of your newly created private app.\\ Img 3 ### Integrate HubSpot Blogs into xpander.ai 1. Go to the **Connectors** section in the sidebar of your xpander.ai dashboard. 2. Select **HubSpot Blogs** from the available integrations. 3. Click **Other auth options**. 4. Enter a **connector name**, e.g., "xpander-hubspot-blogs". 5. Select **Integration User** as the authentication mode. 6. Select **API Key** as the authentication method. 7. Paste the HubSpot access token into the provided field. 8. Choose **Bearer** as the **Auth Type**. 9. Save the configuration. Img 4 ## Integration of HubSpot Blogs into AI Agent Once you've configured your HubSpot Blogs account with the authentication option(s) described above, you can integrate it into your AI agent with xpander.ai: 1. In your xpander.ai dashboard, go to the **Agent Configuration** tab and select **Tools**, then click **Add Tools**. 2. Select **Connectors**. 3. Choose **HubSpot Blogs** with the same **connector name** you configured in the previous section (e.g., xpander-hubspot-blogs). 4. Select the available HubSpot Blogs operations that suit your use case. Img 5 ## AI Agent HubSpot Blogs Prompt Library Below are possible prompts or use cases you can try after integrating HubSpot Blogs into your xpander AI agent: ``` Can you retrieve the details for post {blog_title}? ``` ``` Can you schedule the {blog_titile} post to publish on {future_date}? ``` ``` Can you create a Spanish version of the {blog_title} blog post? ``` ``` Can you fetch all the revision history for our {blog_title} post? ``` ## Related Resources * [Understanding Model Context Protocol (MCP)](/guides/deploy/mcp) * [HubSpot Blogs API Documentation](https://developers.hubspot.com/docs/reference/api/overview) # HubSpot CRM Source: https://docs.xpander.ai/connectors/hubspot-crm Learn how to integrate AI agents with HubSpot CRM using xpander.ai. Create intelligent workflows that automatically engage leads, update contact records, and trigger personalized follow-ups based on real-time customer interactions. ## About HubSpot CRM HubSpot CRM is a customer relationship management (CRM) platform designed to help businesses organize, track, and nurture leads and customers. Key Features of HubSpot CRM: * **Contact Management**: Store and manage customer and lead information in one place. * **Pipeline Management**: Visualize and track the progress of deals through sales stages. * **Email Integration**: Connect with Gmail or Outlook to track email interactions. * **Marketing Tools**: Includes forms, landing pages, email marketing, and automation (in the Marketing Hub). * **Customer Service**: Offers ticketing, live chat, and a knowledge base (in the Service Hub). * **Analytics & Reporting**: Provides insights into sales activity, performance, and marketing metrics. * **Customization**: Users can customize pipelines, fields, dashboards, and more. * **Integration**: Works with tools like Slack, Zoom, Shopify, and hundreds of others. ## Authentication Options Below are possible authentication options you can choose: The simplest way to connect HubSpot CRM is by using xpander.ai's built-in authentication: 1. Go to the **Connectors** section in the sidebar of your xpander.ai dashboard. 2. Select **HubSpot CRM** from the available integrations. 3. Click **Sign in with HubSpot CRM**. 4. Choose the account you want to connect and grant xpander.ai permission to access it. 5. HubSpot CRM is now ready to use. ### Generate a HubSpot CRM API Key 1. Log in to your [HubSpot CRM account](https://www.hubspot.com/products/crm). 2. Click on **Settings** (the gear icon) in the top bar of your dashboard. 3. In the sidebar, click on **Integration**. 4. Select **Private Apps**, then click **Create Private App**.\\ Img 1 5. Enter a name for your app. In the **Scopes** tab, click **Add new scope** and grant the app access to the CRM services appropriate for your use case.\\ Img 2 6. Click **Create App**. 7. Your access token will be available in the **Auth** tab of the newly created private app.\\ Img 3 ### Integrate HubSpot CRM into xpander.ai 1. Go to the **Connectors** section in the sidebar of your xpander.ai dashboard. 2. Select **HubSpot CRM** from the available integrations. 3. Click **Other auth options**. 4. Enter a **connector name**, e.g., "xpander-hubspot-crm". 5. Select **Integration User** as the authentication mode. 6. Select **API Key** as the authentication method. 7. Paste the HubSpot access token into the provided field. 8. Choose **Bearer** as the **Auth Type**. 9. Save the configuration. Img 4 ## Integration of HubSpot CRM into AI Agent Once you've configured your HubSpot CRM account with the authentication option(s) described above, you can integrate it into your AI agent with xpander.ai: 1. In your xpander.ai dashboard, go to the **Agent Configuration** tab and select **Tools**, then click **Add Tools**. 2. Select **Connectors**. 3. Choose **HubSpot CRM** with the same **connector name** you configured in the previous section (e.g., xpander-hubspot-crm). 4. Select the available HubSpot CRM operations that suit your use case. Img 5 ## AI Agent HubSpot CRM Prompt Library Below are possible prompts or use cases you can try after integrating HubSpot CRM into your xpander AI agent: ``` Can you search for all companies that have more than {revenue_amount} in annual revenue? ``` ``` How do I create a custom object schema for tracking our product warranties? ``` ``` How do I add all the contacts from our "Newsletter Subscribers" list to our "Product Launch" campaign list? ``` ``` Can you update our event template to display customer support interactions differently? ``` ## Related Resources * [Understanding Model Context Protocol (MCP)](/guides/deploy/mcp) * [HubSpot CRM API Documentation](https://developers.hubspot.com/docs/reference/api/overview) # AI Agents Connectors Source: https://docs.xpander.ai/connectors/index Connect your AI agents to powerful apps and services with AI-Optimized connectors ## Available Connectors Create workflow & automation aware AI agents that optimize task management. Create scheduling aware AI agents that optimize appointment coordination efficiently. Create project management aware AI agents that streamline collaborative workflow orchestration. Create knowledge sharing aware AI agents that streamline collaborative documentation processes. Create monitoring aware AI agents that optimize infrastructure observability and analytics. Create transformation-smart AI agents that model, test, and deliver trusted data pipelines. Create file sharing aware AI agents that streamline cloud document management workflows. Create capabilities aware AI agents that integrate data, workflows, and automation. Create versatile, workflow aware AI agents that automate repository interactions efficiently. Create issue tracking aware AI agents that automate bug management and task prioritization. Create code search aware AI agents that automate repository analysis and retrieval. Create DevSecOps aware AI agents that automate workflows and enhance productivity. Create analytics aware AI agents that automate insights and performance tracking. Create data warehouse aware AI agents that automate analytics and predictive insights. Create scheduling aware AI agents that automate event planning and coordination. Create document editing aware AI agents that automate drafting and collaboration tasks. Create file management aware AI agents that automate storage and sharing tasks. Create survey aware AI agents that automate data collection and analysis. Create email aware AI agents that automate communication and task management. Create spreadsheet aware AI agents that automate data processing and analysis. Create task management aware AI agents that automate organization and productivity. Create blog optimization aware AI agents that generate, refine, and analyze content. Create CRM automation aware AI agents that streamline sales, support, and marketing. Create customer support aware AI agents that automate inquiries, routing, and insights. Create workflow automation aware AI agents that streamline tasks, triage, and summaries. Create project management aware AI agents that automate tasks, triage, and collaboration. Create insight-powered AI agents that explore, visualize, and drive data-driven decisions. Create meeting insights aware AI agents that automate summaries, tasks, and collaboration. Create workflow optimization aware AI agents that automate tasks, insights, and collaboration. Create knowledge management aware AI agents that summarize, translate, and organize content. Create incident response aware AI agents that automate detection, triage, and resolution. Create insight-driven AI agents that analyze, visualize, and optimize decisions. Create meeting intelligence aware AI agents that transcribe, analyze, and respond. Create communication automation aware AI agents that streamline messaging, tasks, and collaboration. Create incident communication aware AI agents that automate updates, alerts, and transparency. Create database management aware AI agents that query, update, and organize data. Create backend integration aware AI agents that automate data storage and retrieval. Create data-intelligent AI agents that analyze, visualize, and deliver actionable insights. Create weather intelligence aware AI agents that forecast, alert, and optimize operations. Create communication automation aware AI agents that streamline messaging, tasks, and collaboration. Create workflow automation aware AI agents that orchestrate tasks across applications. Create customer support aware AI agents that automate inquiries, triage, and resolution. Create business automation aware AI agents that streamline workflows, insights, and communication. Create meeting productivity aware AI agents that automate summaries, tasks, and collaboration. ## Integration Benefits Let AI agents handle repetitive document and data tasks Give agents the ability to retrieve and use information Build multi-step processes across applications Produce documents, reports, and presentations ## Getting Started 1. Select an app integration from the list above 2. Follow the authentication guide for your chosen service 3. Add service tools to your agent 4. Configure your agent with example prompts 5. Deploy and test your integration # Intercom Source: https://docs.xpander.ai/connectors/intercom Learn how to integrate AI agents with Intercom using xpander.ai. Create intelligent, automated workflows that seamlessly connect your AI agent with Intercom's chat, inbox, and help center features to provide instant, context-aware support across your customer journey. ## About Intercom Intercom is an AI-first customer service platform designed to enhance customer support through automation, real-time communication, and self-service tools. Key Features of Intercom * **AI Agent (Fin)**: Fin is Intercom's AI-powered chatbot that provides instant, accurate answers to customer inquiries 24/7. It learns from every interaction to improve its responses over time. * **AI Copilot**: This tool assists support agents by offering real-time suggestions and information during customer interactions, enhancing efficiency and response quality. * **AI Analyst**: Provides support leaders with insights and recommendations based on customer interactions, helping to identify trends and areas for improvement. * **Integrated Help Center**: Allows businesses to create customizable, multilingual help centers that empower customers to find answers independently, reducing the load on support teams. * **Omnichannel Support**: Intercom enables seamless communication across various channels, including chat, email, and phone, ensuring consistent support experiences. ## Authentication Options Below are possible authentication options you can choose: ### Generate an Intercom API Key 1. Log in to your [Intercom account](https://app.intercom.com/). 2. Click **Settings** in the sidebar. 3. Navigate to the **Integrations** section and click **Developer Hub**.\\ Img 1 4. In the Developer Hub, click **New app**. 5. Enter a name for your app and select the appropriate workspace.\\ Img 2 6. After clicking **Create app**, your access token will be displayed. ### Integrate Intercom into xpander.ai 1. Go to the **Connectors** section in the sidebar of your xpander.ai dashboard. 2. Select **Intercom** from the available integrations. 3. Click **Other auth options**. 4. Enter a **connector name**, e.g., "xpander-intercom". 5. Select **Integration User** as the authentication mode. 6. Select **API Key** as the authentication method. 7. Paste the Intercom access token into the provided field. 8. Choose **Bearer** as the **Auth Type**. 9. Save the configuration. Img 3 ## Integration of Intercom into AI Agent Once you've configured your Intercom account with the authentication option(s) described above, you can integrate it into your AI agent with xpander.ai: 1. In your xpander.ai dashboard, go to the **Agent Configuration** tab and select **Tools**, then click **Add Tools**. 2. Select **Connectors**. 3. Choose **Intercom** with the same **connector name** you configured in the previous section (e.g., xpander-intercom). 4. Select the available Intercom operations that suit your use case. Img 4 ## Expose Intercom as MCP Server Alternatively, you can also expose your Intercom account as an MCP server. To do so: 1. Go to the **Connectors** section in the sidebar of your xpander.ai dashboard. 2. Select **Intercom** with the same **connector name** you configured in the previous section (e.g., xpander-intercom). 3. Click **MCP Configuration**. 4. Enter the MCP configuration into the appropriate settings of the client app you want to use (e.g., Cursor, Windsurf, Claude Desktop, etc.). Img 5 ## AI Agent Intercom Prompt Library Below are possible prompts or use cases you can try after integrating Intercom into your xpander AI agent: ``` Can you create a new support ticket for {customer_name} regarding an issue with {product}? ``` ``` Could you create a new collection in our help center for documentation about {topic}? ``` ``` Please update the article about {topic} to include new information about {feature}. ``` ``` Please search our knowledge base for articles about {topic}. ``` ## Related Resources * [Understanding Model Context Protocol (MCP)](/guides/deploy/mcp) * [Intercom API Documentation](https://developers.intercom.com/docs/references/rest-api/api.intercom.io) # Jira Source: https://docs.xpander.ai/connectors/jira Learn how to integrate AI agents with Jira using xpander.ai. Create intelligent workflows that automatically assign tasks, analyze issue trends, generate reports, and trigger actions based on project activity. ## About Jira Jira is a versatile project management and issue-tracking software developed by Atlassian, widely utilized by software development teams and various other departments to plan, track, and manage work efficiently. Key features include: * **Customizable Workflows**: Adapt Jira to fit your team's processes by customizing issue types, fields, and workflows. * **Agile Boards**: Utilize Scrum and Kanban boards to visualize work, manage sprints, and track progress. * **Reporting and Dashboards**: Generate real-time reports and dashboards to gain insights into team performance and project status. * **Integration Capabilities**: Jira integrates with various development and collaboration tools, including Bitbucket, Confluence, and third-party applications, enhancing its functionality. ## Authentication Options Below are possible authentication options you can choose: The simplest way to connect to Jira is by using xpander.ai's built-in authentication: 1. Go to the **Agentic Connectors** section in the sidebar of your xpander.ai dashboard. 2. Select **Jira** from the available integrations. 3. Click **+ Create new connection**. 4. Enter a **connector name** as desired, e.g., "xpander-jira". 5. Choose **OAuth2** as the authentication method. 6. Click **Authorize xpander.ai**. 7. Grant xpander.ai permission to access your account. 8. Save the configuration. Img 2 ## Integration of Jira into AI Agent Once you've configured your Jira account with the authentication option(s) described above, you can integrate it into your AI agent with xpander.ai: 1. In your xpander.ai dashboard, go to the **Agent Configuration** tab and select **Tools**, then click **Add Tools**. 2. Select **Connectors**. 3. Choose **Jira** with the same **connector name** you configured in the previous section (e.g., xpander-jira). 4. Select the available Jira operations that suit your use case. To grant your agent issue management capabilities, enable the following operations. * **Bulk Get Issues** * **Bulk Create Issues** * **Get Issue Details** * **Edit Issue** * **Assign Issue** * **Delete Issue** 5. Click **Save**, then click **Publish** to publish the updated agent. Img 4 ## AI Agent Jira Prompt Library Below are possible prompts or use cases you can try after integrating Jira into your xpander AI agent: ``` Could you retrieve the audit records from {start_date} to {end_date}? ``` ``` Could you create a new component called {component_name} in the {project_key} project? ``` ``` Can you bulk move these issues to the {project_name} project? ``` ``` Can you retrieve the thumbnail for attachment {attachment_id}? ``` ## Related Resources * [Understanding Model Context Protocol (MCP)](/guides/deploy/mcp) * [Jira API Documentation](https://developer.atlassian.com/cloud/jira/platform/rest/v3/intro/) # Linear Source: https://docs.xpander.ai/connectors/linear Learn how to integrate AI agents with Linear using xpander.ai. Create automated workflows that can triage issues, assign tasks based on workload, update statuses in real-time, and generate progress summaries—streamlining your entire development pipeline. ## About Linear Linear is a modern, purpose-built project management and issue tracking tool designed specifically for software development teams. It streamlines workflows by integrating tasks, sprints, roadmaps, and documentation into a unified, fast, and intuitive interface. Linear key features: * **Issues & Tasks**: Track bugs, features, and tasks with customizable fields, dependencies, and comments. Issues can be organized into projects or linked to sprints (called “Cycles”) for agile planning. * **Projects & Milestones**: Group related issues into projects, define milestones, and monitor progress with visual tools like project graphs and status updates. * **Cycles (Sprints)**: Plan and execute time-boxed iterations to keep teams focused and aligned. * **Roadmaps**: Visualize long-term plans and align the team around strategic goals. * **Real-Time Collaboration**: Comment on issues, tag teammates, and co-edit documents with real-time syncing across devices. * **Integrations**: Connect with tools like GitHub, Slack, Figma, and more to automate workflows and enhance productivity. ## Authentication Options Below are possible authentication options you can choose: ### Generate a Linear API Key 1. Log in to your [Linear app](https://linear.app/). 2. Click on your avatar and select **Settings** from the dropdown menu. 3. In the sidebar, click **Security & access**. 4. In the **Personal API keys** section, click **New API key**.\\ Img 1 5. Enter a name for the key, assign the appropriate permissions, and click **Create**. 6. Save the API key. ### Integrate Linear into xpander.ai 1. Go to the **Connectors** section in the sidebar of your xpander.ai dashboard. 2. Select **Linear** from the available integrations. 3. Click **Enable**. 4. Enter a **connector name**, e.g., "xpander-linear". 5. Select **Integration User** as the authentication mode. 6. Select **API Key** as the authentication method. 7. Paste the Linear API key into the provided field. 8. Choose **Custom** as the **Auth Type**. 9. In the **Custom header name** field, enter `Authorization`. 10. Save the configuration. Img 2 ## Integration of Linear into AI Agent Once you've configured your Linear account with the authentication option(s) described above, you can integrate it into your AI agent with xpander.ai: 1. In your xpander.ai dashboard, go to the **Agent Configuration** tab and select **Tools**, then click **Add Tools**. 2. Select **Connectors**. 3. Choose **Linear** with the same **connector name** you configured in the previous section (e.g., xpander-linear). 4. Select the available Linear operations that suit your use case. Img 3 ## Expose Linear as MCP Server Alternatively, you can also expose your Linear account as an MCP server. To do so: 1. Go to the **Connectors** section in the sidebar of your xpander.ai dashboard. 2. Select **Linear** with the same **connector name** you configured in the previous section (e.g., xpander-linear). 3. Click **MCP Configuration**. 4. Enter the MCP configuration into the appropriate settings of the client app you want to use (e.g., Cursor, Windsurf, Claude Desktop, etc.). Img 4 ## AI Agent Linear Prompt Library Below are possible prompts or use cases you can try after integrating Linear into your xpander AI agent: ``` Could you add a comment to issue #{issue_number} with feedback from the {team_name} team? ``` ``` Could you create a new bug ticket for the login page crash we just discovered? ``` ``` Can you update the priority of issue #{issue_number} to urgent? ``` ``` Can you create a new project named '{project_name}' for our Q4 initiatives? ``` ## Related Resources * [Understanding Model Context Protocol (MCP)](/guides/deploy/mcp) * [Linear API Documentation](https://linear.app/developers) # Looker Source: https://docs.xpander.ai/connectors/looker Learn how to integrate AI agents with Looker using xpander.ai. Create intelligent data workflows that enable AI agents to analyze Looker models, generate actionable insights, and trigger automated business decisions in real time. ## About Looker Looker is a cloud-based enterprise business intelligence (BI) and data analytics platform which is now part of Google Cloud. Key features include: * **LookML Semantic Layer**: Central definition of business logic and metrics, enabling a single source of truth and scalable governance. * **Self-Service Analytics & Visualization**: Users can explore data visually via "Explores," dashboards, and charts without requiring SQL skills. * **Embedded & Extensible Analyticst**: Looker provides robust APIs to embed dashboards into apps/websites and build customized data applications, with options like the Looker Agent for AI workflows * **Scalable In-Database Architecture**: Queries are pushed directly to high-performance cloud warehouses (e.g. BigQuery, Snowflake, Redshift, Vertica) for speed and scale. ## Authentication Options Below are possible authentication options you can choose: ### Generate a Tableau API Token 1. Log in to your [Looker account](https://cloud.google.com/looker?hl=en). 2. In the sidebar of your Looker dashboard, click **Admin**. Img 1 3. In the **Admin** panel sidebar, select **Users**, then choose an existing user or create a new one to grant API access. 4. Under the **API Keys** section for that user, click **Edit Keys**. You’ll receive a **Client ID** and **Client Secret**, which you’ll use to obtain an access token. Img 2 5. Next, obtain an access token by executing the following request: ``` curl -d "client_id=&client_secret=" \ https://.cloud.looker.com/api/4.0/login ``` Note: You can find your account name in your Looker URL. For example, if the URL is [https://xpander.cloud.looker.com](https://xpander.cloud.looker.com), the account name is xpander. 6. Copy your access token and store it somewhere safe. ### Integrate Looker into xpander.ai 1. In your **xpander.ai** dashboard, navigate to the **Connectors** section in the sidebar. 2. Select **Looker** from the list of available integrations. 3. Click **Enable**. 4. Enter a **connector name**, for example: `xpander-looker`. 5. Set the Authentication Mode to **Integration User**. 6. Choose **API Key** as the authentication method. 7. Paste your Looker **Access Token** into the provided field. 8. Set **Auth Type** to **Bearer**. 9. Under **Interface-Specific Settings**, enter the base URL `https://{host}:{port}/api/4.0` * Replace `{host}` with the base URL of your Looker account (e.g., `xpander.cloud.looker.com`). * For `{port}`, use: * `443` if your Looker instance is hosted on Google Cloud, Microsoft Azure, or AWS **and was created on or after 07/07/2020**. * `19999` if it was created **before 07/07/2020**. 10. Save the configuration. Img 3 ## Integration of Looker into AI Agent Once you've configured your Looker account with the authentication option(s) described above, you can integrate it into your AI agent with xpander.ai: 1. In your xpander.ai dashboard, go to the **Agent Configuration** tab and select **Tools**, then click **Add Tools**. 2. Select **Connectors**. 3. Choose **Tableau** with the same **connector name** you configured in the previous section (e.g., xpander-looker). 4. Select the available Looker operations that suit your use case. Img 4 ## Expose Looker as MCP Server Alternatively, you can also expose your Looker account as an MCP server. To do so: 1. Go to the **Connectors** section in the sidebar of your xpander.ai dashboard. 2. Select **Looker** with the same **connector name** you configured in the previous section (e.g., xpander-looker). 3. Click **MCP Configuration**. 4. Enter the MCP configuration into the appropriate settings of the client app you want to use (e.g., Cursor, Windsurf, Claude Desktop, etc.). Img 5 ## AI Agent Looker Prompt Library Below are possible prompts or use cases you can try after integrating Looker into your xpander AI agent: ``` Find me all content items that mention {keyword} across the platform. ``` ``` Show me all favorite content records for user {user_id}. ``` ``` Can you get me the detailed metadata information for content item {content_metadata_id}? ``` ``` Create a new filter named "{filter_name}" of type {filter_type} for dashboard {dashboard_id}. ``` ## Related Resources * [Understanding Model Context Protocol (MCP)](/guides/deploy/mcp) * [Looker API Documentation](https://cloud.google.com/looker/docs/reference/looker-api/latest) # MeetGeek Source: https://docs.xpander.ai/connectors/meetgeek Learn how to integrate AI agents with MeetGeek using xpander.ai. Create intelligent meeting assistants that automatically capture, summarize, and share key discussion points by leveraging MeetGeek's advanced transcription and integration capabilities. ## About MeetGeek MeetGeek is an AI-powered meeting assistant designed to enhance productivity by automating the recording, transcription, summarization, and analysis of meetings. It integrates seamlessly with platforms like Google Calendar, Outlook, etc to provide accurate transcripts and actionable insights. Key Features of MeetGeek: * **Automated Recording & Transcription**which ensures accurate and comprehensive records. * **AI-Generated Summaries**: MeekGeek delivers concise meeting summaries highlighting key points, decisions, and action items, which allows users to quickly grasp the essence of meetings without reviewing entire recordings. * **Integration with Productivity Tools**: MeetGeek integrates with tools like Notion, ClickUp, Trello, HubSpot, and Salesforce, which enables seamless synchronization of meeting content and insights across various platforms. * **Team Collaboration & Knowledge Sharing**: MeetGeek offers features for team collaboration, such as shared meeting libraries, searchable transcripts, and the ability to define team rules for sharing meeting content. * **Conversation Intelligence**: MeetGeek provides analytics on meeting engagement, speaker distribution, meeting sentiment, and other key performance indicators. ## Authentication Options Below are possible authentication options you can choose: ### Generate MeetGeek API Key 1. Log in into your [MeetGeek account](https://meetgeek.ai/). 2. In the sidebar of your dashboard, choose **Integrations** -> **Public API**. Img 1 3. You'll see your MeetGeek API key. Img 2 ### Integrate MeetGeek into Xpander.ai 1. Go to the **Connectors** section in the sidebar of your xpander.ai dashboard. 2. Select **MeetGeek** from the available integrations. 3. Click **Enable**. 4. Fill in the **connector name** as desired, e.g., "xpander-meetgeek". 5. Choose **Integration user** as the authentication mode. 6. Choose **API Key** as the authentication method. 7. Copy and paste your MeetGeek API key into the provided field. 8. Choose **Bearer** as the **auth type**. 9. Save the configuration Img 3 ## Integration of MeetGeek into AI Agent Once you've configured your MeetGeek account with the authentication option(s) described above, you can integrate it into your AI agent with xpander.ai: 1. In your xpander.ai dashboard, go to the **Agent Configuration** tab and select **Tools**, then click **Add Tools**. 2. Select **Connectors**. 3. Choose **MeetGeek** with the same **connector name** you configured in the previous section (e.g., xpander-meetgeek). 4. Select the available MeetGeek operations that suit your use case. Img 4 ## Expose MeetGeek as MCP Server Alternatively, you can also expose your MeetGeek account as an MCP server. To do so: 1. Go to the **Connectors** section in the sidebar of your xpander.ai dashboard. 2. Select **MeetGeek** with the same **connector name** you configured in the previous section (e.g., xpander-meetgeek). 3. Click **MCP Configuration**. 4. Put the MCP configuration into the appropriate settings of the client app you want to use (e.g., Cursor, Windsurf, Claude Desktop, etc.). Img 5 ## AI Agent MeetGeek Prompt Library Below are possible prompts or use cases you can try after integrating MeetGeek into your xpander AI agent: ``` Can you provide a summary of my meeting with {Client_Name} last Thursday? ``` ``` I have a recording of a meeting with {Client_Name} from yesterday. Can you transcribe and analyze it? ``` ``` What meetings did I have last week? ``` ``` Who attended my meeting with {Client_Name} on {Date}? ``` ## Related Resources * [Understanding Model Context Protocol (MCP)](/guides/deploy/mcp) * [MeetGeek API Documentation](https://docs.meetgeek.ai/getting-started/introduction) # Microsoft OneDrive Source: https://docs.xpander.ai/connectors/microsoft-onedrive Learn how to integrate AI agents with Microsoft OneDrive using xpander.ai. Create AI agents that can securely interact with Microsoft OneDrive to manage files and documents across workflows. ## About Microsoft OneDrive **Microsoft OneDrive** is a cloud-based file storage and content management platform built for storing, syncing, sharing, and collaborating on files across devices and Microsoft 365 applications. Key features include: * **Cloud file storage and sync**: Centralized storage for files and folders with automatic synchronization across desktop, web, and mobile devices. * **File and folder management**: Create, upload, organize, move, copy, and delete files and folders with support for large files and rich metadata. * **Collaboration and sharing**: Enable secure file sharing and real-time collaboration with granular permission controls for internal and external users. * **Versioning and recovery**: Maintain version history for files, allowing users and systems to restore previous versions and recover deleted content. * **Security and compliance**: Built-in security features including encryption, access controls, auditing, and compliance with enterprise and regulatory requirements. ## Authentication Options Below are possible authentication options you can choose: The simplest way to connect Microsoft OneDrive is by using xpander.ai's built-in authentication: 1. Go to the **Connectors** section in the sidebar of your xpander.ai dashboard. 2. Select **Microsoft OneDrive** from the available integrations. 3. Click **+ Create new connection**. 4. Enter a **connector name** as desired, e.g., "xpander-onedrive". 5. Choose **OAuth2** as the authentication method. 6. Click **Sign in with Microsoft OneDrive**. 7. Grant xpander.ai permission to access your account. 8. Save the configuration. Img 1 ## Integration of Microsoft OneDrive into an AI Agent Once you’ve configured your Microsoft OneDrive connector with the authentication option described above, you can integrate it into your AI agent with xpander.ai: 1. In your xpander.ai dashboard, navigate to the **Agents** page, then click an agent to open the **Agent Configuration** tab. 2. Select **Tools**, then click **Add Tools**. 3. Select **Connectors**. 4. Choose **Microsoft OneDrive** with the same **connector name** you configured in the previous section (e.g., xpander-onedrive). 5. Select the available Microsoft OneDrive operations that suit your use case. To grant your agent file and folder management capabilities, enable the following operations. * **List Drive Items** * **Create Item in Drive** * **Delete Drive Item (Drive + Item ID)** * **Update Drive Item Metadata (Drive + Item ID)** 6. Click **Deploy** to update your agent. Img 2 ## AI Agent Microsoft OneDrive Prompt Library Below are possible prompts or use cases you can try after integrating Microsoft OneDrive into your xpander.ai AI agent: ``` List all folders in my one drive. ``` ``` Change folder name to . ``` ``` Send to the recycle bin. ``` ``` Add an example.txt file to the ## Related Resources * [Using Tools & Connectors in the xpander.ai platform](/guides/agents/tools-connectors) * [Microsoft OneDrive Documentation](https://learn.microsoft.com/en-us/onedrive/) # Microsoft Outlook Source: https://docs.xpander.ai/connectors/microsoft-outlook Learn how to integrate AI agents with Microsoft Outlook using xpander.ai. Create intelligent AI agents that can securely access your Outlook email, calendar, and contacts to complete scheduling and communication tasks. ## About Microsoft Outlook **Microsoft Outlook** is a cloud-based communication and productivity platform designed to help manage email, calendars, and contacts for individuals and organizations. Key features include: * **Email and messaging**: Send, receive, organize, and manage email conversations, including attachments, folders, and rules. * **Calendar and scheduling**: Manage calendars, meetings, and events with scheduling, availability, and reminder support. * **Contacts and people management**: Store and manage contact information and people data across personal and organizational directories. * **Security and compliance**: Enterprise-grade security, data protection, retention, and compliance controls across communication data. ## Authentication Options Below are possible authentication options you can choose: The simplest way to connect Microsoft Outlook is by using xpander.ai's built-in authentication: 1. Go to the **Connectors** section in the sidebar of your xpander.ai dashboard. 2. Select **Outlook** from the available integrations. 3. Click **+ Create new connection**. 4. Enter a **connector name** as desired, e.g., "xpander-outlook". 5. Choose **OAuth2** as the authentication method. 6. Click **Sign in with Outlook**. 7. Grant xpander.ai permission to access your account. 8. Save the configuration. Img 1 ## Integration of Microsoft Outlook into an AI Agent Once you’ve configured your Microsoft Outlook connector with the authentication option described above, you can integrate it into your AI agent with xpander.ai: 1. In your xpander.ai dashboard, navigate to the **Agents** page, then click an agent to open the **Agent Configuration** tab. 2. Select **Tools**, then click **Add Tools**. 3. Select **Connectors**. 4. Choose **Outlook** with the same **connector name** you configured in the previous section (e.g., xpander-outlook). 5. Select the available Microsoft Outlook operations that suit your use case. To grant your agent email management and scheduling capabilities, enable the following operations. * **List Calendar Events** * **Create Event** * **Update Event Details** * **Delete Event** * **Create Message** * **Send Draft Message** * **List User Messages** 6. Click **Deploy** to update your agent. Img 2 ## AI Agent Microsoft Outlook Prompt Library Below are possible prompts or use cases you can try after integrating Microsoft Outlook into your xpander.ai AI agent: ``` List all messages in my email inbox. ``` ``` What events are in my calendar for tomorrow. ``` ``` Create a new event name for 6pm tomorrow. ``` ``` Send an email with the subject and body to . ``` Gif 1 ## Related Resources * [Using Tools & Connectors in the xpander.ai platform](/guides/agents/tools-connectors) * [Microsoft Outlook Documentation](https://support.microsoft.com/en-us/outlook) # Microsoft SharePoint Source: https://docs.xpander.ai/connectors/microsoft-sharepoint Learn how to integrate AI agents with Microsoft SharePoint using xpander.ai. Create intelligent AI agents that can securely access SharePoint sites, lists, and documents to complete collaboration tasks. ## About Microsoft SharePoint **Microsoft SharePoint** is a cloud-based collaboration and content management platform for creating, managing, and sharing organizational content, sites, and structured data. Key features include: * **Sites and team collaboration**: Create and manage team sites, communication sites, and shared workspaces. * **Document and content management**: Store, organize, and manage documents in libraries with metadata, versioning, and content types. * **Lists and structured data**: Create and manage lists to track structured business data with custom fields and views. * **Sharing and permissions**: Control access to sites, lists, and documents with role-based permissions and sharing policies. * **Security and compliance**: Enterprise-grade security, governance, and compliance controls for organizational content. ## Authentication Options Below are possible authentication options you can choose: The simplest way to connect Microsoft SharePoint is by using xpander.ai's built-in authentication: 1. Go to the **Connectors** section in the sidebar of your xpander.ai dashboard. 2. Select **Microsoft SharePoint** from the available integrations. 3. Click **+ Create new connection**. 4. Enter a **connector name** as desired, e.g., "xpander-sharepoint". 5. Choose **OAuth2** as the authentication method. 6. Click **Sign in with Microsoft SharePoint**. 7. Grant xpander.ai permission to access your account. 8. Save the configuration. Img 1 ## Integration of Microsoft SharePoint into an AI Agent Once you’ve configured your Microsoft SharePoint connector with the authentication option described above, you can integrate it into your AI agent with xpander.ai: 1. In your xpander.ai dashboard, navigate to the **Agents** page, then click an agent to open the **Agent Configuration** tab. 2. Select **Tools**, then click **Add Tools**. 3. Select **Connectors**. 4. Choose **Microsoft SharePoint** with the same **connector name** you configured in the previous section (e.g., xpander-sharepoint). 5. Select the available Microsoft SharePoint operations that suit your use case. To grant your agent site and file management capabilities, enable the following operations. * **List All Drives** * **List Drive Items** * **Get Drive List** * **List Site Pages** * **List Site Drives** * **List All Sites** * **List Followed Sites** 6. Click **Deploy** to update your agent. Img 2 ## AI Agent Microsoft SharePoint Prompt Library Below are possible prompts or use cases you can try after integrating Microsoft SharePoint into your xpander.ai AI agent: ``` List the sites I'm currently following. ``` ``` Get a list of drives in site . ``` ``` Create a new list named . ``` ``` List all the pages in site . ``` ## Related Resources * [Using Tools & Connectors in the xpander.ai platform](/guides/agents/tools-connectors) * [Microsoft SharePoint Documentation](https://learn.microsoft.com/en-us/sharepoint/) # Microsoft Teams Source: https://docs.xpander.ai/connectors/microsoft-teams Learn how to integrate AI agents with Microsoft Teams using xpander.ai. Create intelligent AI agents that can securely access channels, chats, meetings, and files to automate tasks and improve team collaboration. ## About Microsoft Teams **Microsoft Teams** is a cloud-based collaboration platform that enables organizations to communicate, meet, and work together in a unified workspace across chat, meetings, calls, and file sharing. Key features include: * **Channels and team collaboration**: Create teams and channels to organize conversations by department, project, or topic, with threaded discussions and shared workspaces. * **Chat and messaging**: Communicate instantly through 1:1 chats, group chats, and channel messages with rich text, mentions, and file attachments. * **Meetings and calls**: Host online meetings, video conferences, webinars, and voice calls with screen sharing and recording capabilities. * **File sharing and collaboration**: Store and collaborate on shared files directly within Teams, integrated with Microsoft 365 apps. * **Security and compliance**: Enterprise-grade security, identity management, and compliance controls built into the Microsoft 365 ecosystem. ## Authentication Options Below are possible authentication options you can choose: The simplest way to connect Microsoft Teams is by using xpander.ai's built-in authentication: 1. Go to the **Connectors** section in the sidebar of your xpander.ai dashboard. 2. Select **Microsoft Teams** from the available integrations. 3. Click **+ Create new connection**. 4. Enter a **connector name** as desired, e.g., "xpander-teams". 5. Choose **OAuth2** as the authentication method. 6. Click **Sign in with Microsoft Teams**. 7. Grant xpander.ai permission to access your account. 8. Save the configuration. Img 1 ## Integration of Microsoft Teams into an AI Agent Once you’ve configured your Microsoft Teams connector with the authentication option described above, you can integrate it into your AI agent with xpander.ai: 1. In your xpander.ai dashboard, navigate to the **Agents** page, then click an agent to open the **Agent Configuration** tab. 2. Select **Tools**, then click **Add Tools**. 3. Select **Connectors**. 4. Choose **Microsoft Teams** with the same **connector name** you configured in the previous section (e.g., xpander-teams). 5. Select the available Microsoft Teams operations that suit your use case. To grant your agent channel management and chat capabilities, enable the following operations. * **List User Chats** * **Create Chat** * **Create Chat Message** * **List Chat Messages** * **Create Joined Team Channels** * **List Joined Team Channel Messages** 6. Click **Deploy** to update your agent. Img 2 ## AI Agent Microsoft Teams Prompt Library Below are possible prompts or use cases you can try after integrating Microsoft Teams into your xpander.ai AI agent: ``` List all the teams I’m a member of. ``` ``` Get all channels in team . ``` ``` Create a new channel named in team . ``` ## Related Resources * [Using Tools & Connectors in the xpander.ai platform](/guides/agents/tools-connectors) * [Microsoft Teams Documentation](https://learn.microsoft.com/en-us/microsoftteams/) # Mixpanel Source: https://docs.xpander.ai/connectors/mixpanel Learn how to integrate AI agents with Mixpanel using xpander.ai. Build intelligent workflows that query event data, analyze user behavior, track funnels, and generate insights from your product analytics. ## About Mixpanel Mixpanel is a powerful product analytics platform that helps teams understand how users interact with their products through event-based tracking and behavioral analysis. Key features include: * **Event Tracking**: Track user actions and interactions in real time, from page views and clicks to custom business events, enabling granular understanding of user behavior. * **Segmentation**: Slice and dice event data by any property — user attributes, event properties, or time ranges — to uncover patterns and trends across different user segments. * **Funnels**: Define multi-step conversion funnels to measure drop-off rates, identify bottlenecks, and optimize user journeys from sign-up to activation and beyond. * **Retention Analysis**: Measure how often users return to your product over time, track engagement curves, and identify what drives long-term user retention. * **User Profiles**: Maintain rich user profiles with demographic, behavioral, and custom properties, enabling targeted analysis and personalized experiences. * **Cohort Analysis**: Group users based on shared behaviors or attributes and compare how different cohorts engage with your product over time. ## Authentication Options Below are possible authentication options you can choose: ### Generate Mixpanel API Credentials 1. Log in to your [Mixpanel dashboard](https://mixpanel.com). 2. Navigate to **Settings** → **Project Settings**. 3. Under **Access Keys**, locate your **API Secret** — copy and store it securely. 4. Note your **Project ID** from the project settings page (you may need this for certain queries). ### Integrate Mixpanel into xpander.ai 1. In your xpander.ai dashboard, go to the **Connectors** section in the sidebar. 2. Select **Mixpanel** from the list of available integrations. 3. Click **Enable**. 4. Enter a **connector name**, e.g., "xpander-mixpanel". 5. Choose **Integration User** as the authentication mode. 6. Select **API Key** as the authentication method. 7. Set the **Auth Type** to **Custom**. 8. In the **Custom header name** field, type: `Authorization` 9. In the **Value** field, enter `Basic` followed by the Base64-encoded value of your API Secret with a trailing colon. For example, if your API Secret is `abc123`, encode `abc123:` in Base64 and enter: `Basic YWJjMTIzOg==` 10. In the **Interface specific settings** section, set the server URL to: `https://mixpanel.com/api/query` * For EU Data Residency: `https://eu.mixpanel.com/api/query` * For India Data Residency: `https://in.mixpanel.com/api/query` 11. Save the configuration. To encode your API Secret for Basic auth, run the following command in your terminal: ```bash theme={"dark"} echo -n "YOUR_API_SECRET:" | base64 ``` Then prepend `Basic ` to the output value. ## Integration of Mixpanel into AI Agent Once you've configured your Mixpanel account with the authentication option(s) described above, you can integrate it into your AI agent with xpander.ai: 1. In your xpander.ai dashboard, go to the **Agent Configuration** tab and select **Tools**, then click **Add Tools**. 2. Select **Connectors**. 3. Choose **Mixpanel** with the same **connector name** you configured in the previous section (e.g., xpander-mixpanel). 4. Select the available Mixpanel operations that suit your use case. ### Available Operations The Mixpanel connector provides the following operations: **Event Analytics** | Operation | Description | | ---------------------- | ---------------------------------------------------------------------------- | | Get Events Data | Retrieve event counts over a date range with daily/hourly/weekly granularity | | Get Common Event Names | List all tracked event names in the project | | Get Top Events Today | Show the most popular events with percentage change vs. previous period | **Segmentation** | Operation | Description | | ------------------------------- | ----------------------------------------------------------- | | Get Segmented Event Data | Segment events by any property with date range filtering | | Get Average of Event Expression | Calculate the average of a numeric event property over time | | Get Numeric Segmented Data | Get numeric breakdowns of event data | | Get Sum of Event Expression | Calculate the sum of a numeric event property over time | **Event Properties** | Operation | Description | | ---------------------------- | ----------------------------------------------------------- | | Get Top Event Property Names | List the most common properties for a given event | | Get Top Property Values | Show the most frequent values for a specific event property | | Get Event Property Data | Retrieve detailed property data for events | **Funnels** | Operation | Description | | ------------------------ | ---------------------------------------------- | | Get Funnel Data | Retrieve conversion data for a specific funnel | | Get Funnel Names and IDs | List all configured funnels in the project | **User Analytics** | Operation | Description | | ----------------- | ----------------------------------------------- | | Engage Query | Query user profiles with filters and pagination | | Get Activity Feed | Retrieve the activity stream for specific users | | List Cohorts | List all defined user cohorts | **Retention** | Operation | Description | | ---------------------------- | ----------------------------------------------------- | | Get Retention Data | Measure user retention over configurable time windows | | Get Addiction Retention Data | Analyze frequency-based retention patterns | **Advanced** | Operation | Description | | --------------- | --------------------------------------------------------------------------- | | Query JQL | Run custom JQL (JavaScript Query Language) expressions for complex analysis | | Get Report Data | Retrieve data from saved Insights reports by bookmark ID | ## AI Agent Mixpanel Prompt Library Below are possible prompts or use cases you can try after integrating Mixpanel into your xpander AI agent: ``` What events are being tracked in our Mixpanel project? ``` ``` Show me Login event trends from {start_date} to {end_date}. ``` ``` Show me Page View events segmented by the page property over the last 2 weeks. ``` ``` What are the top events today and how do they compare to yesterday? ``` ``` Show me the activity feed for user {distinct_id} from the last 7 days. ``` ``` Show me our user profiles — who are our enterprise plan users? ``` ``` What are the most common values for the connector_type property of Add Connector events? ``` ``` What is the average number of API Call events per day this month? ``` ## Related Resources * [Mixpanel Documentation](https://docs.mixpanel.com) * [Mixpanel Query API Reference](https://developer.mixpanel.com/reference/query-api) # Monday Source: https://docs.xpander.ai/connectors/monday Learn how to integrate AI agents with Monday using xpander.ai. Create intelligent workflows that automatically assign tasks, prioritize requests, and resolve issues by embedding AI-driven decision-making directly into your Monday boards. ## About Monday Monday.com is a cloud-based work operating system (Work OS) that enables teams to build, manage, and customize workflows for projects, tasks, and everyday operations. It offers a visual and flexible platform designed to enhance collaboration, automate processes, and integrate with various tools, catering to a wide range of industries and team sizes. Monday key features: * **Customizable Workflows**: Users can tailor boards to fit specific project needs, using a variety of column types and views (such as Kanban, Gantt, and calendar) to visualize work. * **Automation**: The platform supports automation of repetitive tasks, such as status updates and notifications, reducing manual work. * **Integrations**: Monday.com integrates with numerous third-party applications, including Slack, Microsoft Teams, Google Workspace, and Adobe Creative Cloud, allowing for seamless workflow across tools. * **Collaboration Tools**: Features like real-time updates, file sharing, and comment threads facilitate team communication and collaboration within the platform. * **No-Code/Low-Code Development**: With its open API and app framework, users can develop custom applications and extensions without extensive coding knowledge. ## Authentication Options Below are possible authentication options you can choose: ### Generate a Monday API Key 1. Log in to your [Monday account](https://monday.com). 2. Click your profile icon in the top-right corner, then select **Developers**. Img 1 3. In the sidebar, under the **My access tokens** section, you’ll find your API key. Img 2 ### Integrate Monday into xpander.ai 1. In your xpander.ai dashboard, go to the **Connectors** section in the sidebar. 2. Select **Monday** from the available integrations. 3. Click **Enable**. 4. Enter a **connector name**, e.g., "xpander-monday". 5. Select **Integration User** for the authentication mode. 6. Choose **API Key** as the authentication method. 7. Paste your Monday API key into the provided field. 8. Set the **Auth Type** to **Basic**. 9. Save the configuration. Img 3 ## Integration of Monday into AI Agent Once you've configured your Monday account with the authentication option(s) described above, you can integrate it into your AI agent with xpander.ai: 1. In your xpander.ai dashboard, go to the **Agent Configuration** tab and select **Tools**, then click **Add Tools**. 2. Select **Connectors**. 3. Choose **Monday** with the same **connector name** you configured in the previous section (e.g., xpander-moday). 4. Select the available Monday operations that suit your use case. Img 4 ## Expose Monday as MCP Server Alternatively, you can also expose your Monday account as an MCP server. To do so: 1. Go to the **Connectors** section in the sidebar of your xpander.ai dashboard. 2. Select **Monday** with the same **connector name** you configured in the previous section (e.g., xpander-monday). 3. Click **MCP Configuration**. 4. Enter the MCP configuration into the appropriate settings of the client app you want to use (e.g., Cursor, Windsurf, Claude Desktop, etc.). Img 5 ## AI Agent Monday Prompt Library Below are possible prompts or use cases you can try after integrating Monday into your xpander AI agent: ``` Can you create a new {team_type} team called {team_name}? ``` ``` Can you retrieve all updates related to the {task_name} item? ``` ``` Could you create a new workspace for the {department_name} team with {workspace_type} access? ``` ``` Can you add our new team member {name} to the {project_name} board? ``` ## Related Resources * [Understanding Model Context Protocol (MCP)](/guides/deploy/mcp) * \[Monday API Documentation]\([https://developer.monday.com/API](https://developer.monday.com/API) reference/) # MongoDB Atlas Source: https://docs.xpander.ai/connectors/mongodb-atlas Learn how to integrate AI agents with MongoDB Atlas using xpander.ai. Enable intelligent workflows that query, insert, update, and delete data across your MongoDB collections, run aggregation pipelines, and discover database schemas. ## About MongoDB Atlas MongoDB Atlas is a fully managed cloud database service built on MongoDB — the most popular NoSQL document database. It provides a flexible, scalable, and developer-friendly platform for modern applications. Key features include: * **Document Model**: MongoDB stores data as flexible JSON-like documents, making it easy to model complex, hierarchical data structures without rigid schemas. * **Multi-Cloud Deployment**: Atlas runs on AWS, Azure, and Google Cloud, offering global clusters, automated failover, and cross-region replication for high availability. * **Full-Text Search**: Built-in Atlas Search powered by Apache Lucene enables rich text search capabilities directly on your MongoDB data without external search engines. * **Aggregation Framework**: MongoDB's powerful aggregation pipeline supports complex data transformations, grouping, filtering, and analytics directly within the database. * **Security & Compliance**: Atlas provides encryption at rest and in transit, network isolation, role-based access control, and compliance with SOC 2, HIPAA, PCI DSS, and GDPR. * **Scalability**: From serverless instances for development to dedicated clusters handling millions of operations per second, Atlas scales with your needs. ## Authentication The MongoDB Atlas connector currently supports **API Key authentication only** in xpander.ai. ### Supported method * **Auth Method:** API Key * **Header Name:** `x-mongodb-uri` * **Header Value:** your full MongoDB connection string Example value: ```text theme={"dark"} mongodb+srv://:@cluster0.xxxxx.mongodb.net/ ``` ### MongoDB-side requirements On the MongoDB side, use standard MongoDB **username/password** credentials in the connection string. ### Configure in xpander.ai 1. In xpander.ai, open **Connectors**. 2. Select **MongoDB Atlas** and click **Create new connection**. 3. Set **Connection name**. 4. Set **Connection access** (for example, `Personal`). 5. Select **API Key** as the authentication method. 6. In the API Key section, choose type **Custom**. 7. Set the custom header name to `x-mongodb-uri`. 8. Paste your MongoDB connection string as the header value. 9. Click **Save**. MongoDB Atlas connection configuration ## Integration of MongoDB Atlas into AI Agent Once you've configured your MongoDB Atlas connector with the authentication option(s) described above, you can integrate it into your AI agent with xpander.ai: 1. In your xpander.ai dashboard, go to the **Agent Configuration** tab and select **Tools**, then click **Add Tools**. 2. Select **Connectors**. 3. Choose **MongoDB Atlas** with the same **connector name** you configured in the previous section (e.g., xpander-mongodb). 4. Select the available MongoDB operations that suit your use case. ### Available Operations The MongoDB Atlas connector provides the following operations: **Discovery (Control Plane)** | Operation | Description | | ------------------------ | ----------------------------------------------------------- | | List Databases | Returns all databases accessible by the configured user | | List Collections | Returns all collection names in a specified database | | List Indexes | Returns all indexes defined on a collection | | Get Collection Stats | Returns document count, storage size, and index information | | Sample Collection Schema | Samples documents to detect field names and types | **Data Plane — Read** | Operation | Description | | ------------------------ | ---------------------------------------------------------------------------- | | Find Documents | Query with filter, projection, sort, limit, and skip | | Find One Document | Return the first document matching a filter | | Count Documents | Count documents matching a filter | | Get Distinct Values | Get unique values for a specific field | | Run Aggregation Pipeline | Execute MongoDB aggregation pipelines ($match, $group, $sort, $lookup, etc.) | **Data Plane — Write** | Operation | Description | | --------------------- | --------------------------------------------------------- | | Insert One Document | Insert a single document | | Insert Many Documents | Batch insert multiple documents | | Update One Document | Update the first matching document using update operators | | Update Many Documents | Update all matching documents | | Replace One Document | Replace an entire document | | Delete One Document | Delete the first matching document | | Delete Many Documents | Delete all matching documents | ## AI Agent MongoDB Atlas Prompt Library Below are possible prompts or use cases you can try after integrating MongoDB Atlas into your xpander AI agent: ``` What databases are available and how many collections does each one have? ``` ``` Show me the schema of the {collection_name} collection in {database_name}. ``` ``` Find all documents in {collection_name} where {field} is greater than {value}, sorted by {sort_field} descending. ``` ``` What are the top 10 {category_field} values by document count in {collection_name}? ``` ``` Insert a new document into {collection_name} with the following fields: {field1}: {value1}, {field2}: {value2}. ``` ``` Update all documents in {collection_name} where {condition_field} equals {value} — set {update_field} to {new_value}. ``` ``` Run an aggregation on {collection_name}: group by {field}, calculate the average {numeric_field}, and sort by the result. ``` ``` How many documents in {collection_name} were created in the last 30 days? ``` ## Related Resources * [MongoDB Atlas Documentation](https://www.mongodb.com/docs/atlas/) # Notion Source: https://docs.xpander.ai/connectors/notion Learn how to integrate AI agents with Notion using xpander.ai. Create intelligent workflows that automate tasks, generate content, summarize notes, and enhance decision-making. ## About Notion Notion is a highly versatile productivity platform that combines note-taking, task management, databases, and collaboration tools into a single, customizable workspace. It's designed to help individuals and teams organize information, manage projects, and streamline workflows. Key features include: * **All-in-One Workspace**: Notion allows users to create and organize notes, tasks, wikis, and databases within a unified interface. This flexibility enables users to tailor their workspace to fit personal or team needs. * **Block-Based Structure**: Content in Notion is built using "blocks," which can be text, images, checklists, code snippets, or embedded files. This modular approach allows for easy customization and rearrangement of content. * **Templates**: Notion offers a vast gallery of pre-built templates for various use cases, including project management, personal planning, and documentation. These templates help users get started quickly and can be customized as needed. * **AI Integration**: Notion AI assists users by generating content drafts, summarizing notes, translating text, and providing writing suggestions. It also offers features like AI Meeting Notes and Enterprise Search to enhance productivity. * **Calendar Integration**: With Notion Calendar, users can link database entries to calendar events, enabling efficient planning and task tracking. It syncs with Google Calendar for consolidated scheduling. ## Authentication Options Below are possible authentication options you can choose: The simplest way to connect Notion is by using xpander.ai's built-in authentication: 1. Go to the **Connectors** section in the sidebar of your xpander.ai dashboard. 2. Select **Notion** from the available integrations. 3. Click **Sign in with Notion**. 4. Grant xpander.ai permission to access your Notion workspace. 5. Your Notion integration is now ready to use. ### Generate a Notion API Key 1. Log in to your [Notion Integrations dashboard](https://www.notion.so/profile/integrations) and click **New Integration**. Img 1 2. Under **Associated workspace**, choose your Notion workspace.\ Under **Type**, select **Internal**. Img 2 3. After clicking **Save**, you'll see your Notion API key under the **Internal Integration Secret** section. ### Integrate Notion into xpander.ai 1. Go to the **Connectors** section in the sidebar of your xpander.ai dashboard. 2. Select **Notion** from the available integrations. 3. Click **Other auth options**. 4. Enter a **connector name**, e.g., "xpander-notion". 5. Choose **Integration User** as the authentication mode. 6. Select **API Key** as the authentication method. 7. Paste the Notion API key into the provided field. 8. Set the **Auth Type** to **Bearer**. 9. Save the configuration. Img 3 ## Integration of Notion into AI Agent Once you've configured your Notion account with the authentication option(s) described above, you can integrate it into your AI agent with xpander.ai: 1. In your xpander.ai dashboard, go to the **Agent Configuration** tab and select **Tools**, then click **Add Tools**. 2. Select **Connectors**. 3. Choose **Notion** with the same **connector name** you configured in the previous section (e.g., xpander-notion). 4. Select the available Notion operations that suit your use case. Img 4 ## Expose Notion as MCP Server Alternatively, you can also expose your Notion account as an MCP server. To do so: 1. Go to the **Connectors** section in the sidebar of your xpander.ai dashboard. 2. Select **Notion** with the same **connector name** you configured in the previous section (e.g., xpander-notion). 3. Click **MCP Configuration**. 4. Enter the MCP configuration into the appropriate settings of the client app you want to use (e.g., Cursor, Windsurf, Claude Desktop, etc.). Img 5 ## AI Agent Notion Prompt Library Below are possible prompts or use cases you can try after integrating Notion into your xpander AI agent: ``` Can you search for all pages related to {project_name} in our workspace? ``` ``` Can you retrieve all tasks assigned to {team_member} from our project tracker? ``` ``` Can you delete the outdated section about {old_feature} from our documentation? ``` ``` Can you show me all unresolved comments on our {document_name} document? ``` ## Related Resources * [Understanding Model Context Protocol (MCP)](/guides/deploy/mcp) * [Notion API Documentation](https://developers.notion.com/reference/intro) # PagerDuty Source: https://docs.xpander.ai/connectors/pagerduty Learn how to integrate AI agents with PagerDuty using xpander.ai. Create intelligent workflows that automatically detect incidents, analyze their impact, and trigger the appropriate on-call responders. ## About PagerDuty PagerDuty is a cloud-based incident management and digital operations platform designed to help organizations detect, respond to, and resolve critical issues in real time. Key features include: * **Incident Management**: Automates the detection and resolution of incidents, ensuring rapid response to minimize downtime. * **On-Call Scheduling**: Manages on-call rotations and escalations to ensure the right personnel are notified during incidents. * **AIOps**: Utilizes artificial intelligence to reduce alert noise and accelerate issue triage. * **Automation**: Streamlines repetitive tasks and workflows, enhancing operational efficiency. * **Status Pages**: Provides real-time system status updates to stakeholders and customers. * **Customer Service Operations**: Bridges support and engineering teams to improve customer experiences. ## Authentication Options Below are possible authentication options you can choose: ### Generate a PagerDuty API Key 1. Sign in to your [PagerDuty account](https://app.pagerduty.com/). 2. Navigate to **Integrations**, then select **API Access Keys** under **Developer Tools**: Img 1 3. Click **Create New API Key**. 4. Enter a description to help you identify the key. 5. Click **Create Key**—your API key will be displayed immediately after. Img 2 ### Integrate PagerDuty into xpander.ai 1. Go to the **Connectors** section in the sidebar of your xpander.ai dashboard. 2. Select **PagerDuty** from the available integrations. 3. Click **Enable**. 4. Enter a **connector name**, e.g., "xpander-pagerduty". 5. Select **Integration User** as the authentication mode. 6. Select **API Key** as the authentication method. 7. Paste the PagerDuty API key into the provided field using the following format:\ `Token token=[YOUR_API_KEY]` 8. Choose **Custom** as the **Auth Type**. 9. Under **Custom header name**, type `Authorization`. 10. Save the configuration. Img 3 ## Integration of PagerDuty into AI Agent Once you've configured your PagerDuty account with the authentication option(s) described above, you can integrate it into your AI agent with xpander.ai: 1. In your xpander.ai dashboard, go to the **Agent Configuration** tab and select **Tools**, then click **Add Tools**. 2. Select **Connectors**. 3. Choose **PagerDuty** with the same **connector name** you configured in the previous section (e.g., xpander-pagerduty). 4. Select the available PagerDuty operations that suit your use case. Img 4 ## Expose PagerDuty as MCP Server Alternatively, you can also expose your PagerDuty account as an MCP server. To do so: 1. Go to the **Connectors** section in the sidebar of your xpander.ai dashboard. 2. Select **PagerDuty** with the same **connector name** you configured in the previous section (e.g., xpander-pagerduty). 3. Click **MCP Configuration**. 4. Enter the MCP configuration into the appropriate settings of the client app you want to use (e.g., Cursor, Windsurf, Claude Desktop, etc.). Img 5 ## AI Agent PagerDuty Prompt Library Below are possible prompts or use cases you can try after integrating PagerDuty into your xpander AI agent: ``` What is the current status of our {business_name} business service? ``` ``` What's the average resolution time for incidents across all our services during {date_range}? ``` ``` How can we update our service orchestration to route critical database alerts to {team_name}? ``` ``` Which incidents are currently impacting our top-level business services? ``` ## Related Resources * [Understanding Model Context Protocol (MCP)](/guides/deploy/mcp) * \[PagerDuty API Documentation]\([https://developer.pagerduty.com/API](https://developer.pagerduty.com/API) reference/) # Power BI Source: https://docs.xpander.ai/connectors/power-bi Learn how to integrate AI agents with Power BI using xpander.ai. Create intelligent dashboards that leverage natural language queries, automated insights, and predictive analytics for real-time, data-driven decision-making. ## About Power BI Power BI is Microsoft's cloud-based business intelligence (BI) platform that enables users to connect to a wide range of data sources, transform and model data, and create rich visual reports and dashboards. Key features include: * **Data connectivity**: Connect to 100+ data sources including Excel, SQL, Azure, Google BigQuery, Snowflake, Salesforce, PDFs, and more. * **Power Query**: Integrated ETL engine (also in Excel/Dataflows) to clean, transform, and mash up data using M‑code. * **Data modeling with DAX**: Use Data Analysis Expressions (DAX) to build measures, calculated columns, dynamic filters, and power calculations. * **Visualizatio**: Drag‑and‑drop visuals, custom visuals via Marketplace, interactive dashboards, report page, Q\&A (natural‑language querying), paginated reports, goals/KPI tracking. ## Authentication Options Below are possible authentication options you can choose: The simplest way to connect Power BI is by using xpander.ai's built-in authentication: 1. Go to the **Connectors** section in the sidebar of your xpander.ai dashboard. 2. Select **Power BI** from the available integrations. 3. Click **Sign in with Power BI**. 4. Grant xpander.ai permission to access your account. 5. Your Power BI integration is now ready to use. ### Generate a Power BI API Token 1. Log in to [Azure Portal](https://portal.azure.com/). 2. Create and register an app to access the Power BI API. To do this, in the sidebar, select **Microsoft Entra ID**. Img 1 3. Under the **Manage** section, select **App registrations** and click **New registration**. Img 2 4. Provide an app name and choose the **Supported account types** option that fits your use case. Then, click **Register**. 5. After creating the app, note down the **Client ID** and **Tenant ID**. You’ll need these credentials later to obtain an access token. 6. In **Microsoft Entra ID**, go to **App registrations** > **All applications**, and select your newly created app. Img 3 7. Under **Manage**, select **Certificates & secrets**, then click **New client secret**. Save the secret value securely. Img 4 8. Ensure your app does **not** have any admin-consent-required permissions. Follow [these steps in the Azure documentation](https://learn.microsoft.com/en-us/fabric/admin/enable-service-principal-admin-apis#how-to-check-if-your-app-has-admin-consent-required-permissions) to verify. 9. In your Power BI account, enable the Power BI Service admin settings by following [Step 3 in this guide](https://learn.microsoft.com/en-us/power-bi/developer/embedded/embed-service-principal?tabs=azure-portal#step-3---enable-the-power-bi-service-admin-settings). 10. In the dashboard of your desired Power BI workspace, go to **Manage access** and add your newly created app as a **Member** or **Admin** by searching for its name. Img 5 11. Finally, obtain your access token by executing the following request: ```bash theme={"dark"} curl -X POST \ -H "Content-Type: application/x-www-form-urlencoded" \ -d "grant_type=client_credentials" \ -d "client_id=" \ -d "client_secret=" \ -d "scope=https://analysis.windows.net/powerbi/api/.default" \ https://login.microsoftonline.com//oauth2/v2.0/token ``` Replace the placeholders with your credentials from previous steps, and store the access token securely. ### Integrate Power BI into xpander.ai 1. In your xpander.ai dashboard, go to the **Connectors** section in the sidebar. 2. Select **Power BI** from the available integrations. 3. Click **Other auth options**. 4. Enter a **connector name**, e.g., "xpander-power-bi". 5. Choose **Integration User** as the authentication mode. 6. Select **API Key** as the authentication method. 7. Paste your Power BI access token into the provided field. 8. Set the **Auth Type** to **Bearer**. 9. Save the configuration. Img 6 ## Integration of Power BI into AI Agent Once you've configured your Power BI account with the authentication option(s) described above, you can integrate it into your AI agent with xpander.ai: 1. In your xpander.ai dashboard, go to the **Agent Configuration** tab and select **Tools**, then click **Add Tools**. 2. Select **Connectors**. 3. Choose **Power BI** with the same **connector name** you configured in the previous section (e.g., xpander-power-bi). 4. Select the available Power BI operations that suit your use case. Img 7 ## Expose Power BI as MCP Server Alternatively, you can also expose your Power BI account as an MCP server. To do so: 1. Go to the **Connectors** section in the sidebar of your xpander.ai dashboard. 2. Select **Power BI** with the same **connector name** you configured in the previous section (e.g., xpander-power-bi). 3. Click **MCP Configuration**. 4. Enter the MCP configuration into the appropriate settings of the client app you want to use (e.g., Cursor, Windsurf, Claude Desktop, etc.). Img 8 ## AI Agent Power BI Prompt Library Below are possible prompts or use cases you can try after integrating Power BI into your xpander AI agent: ``` Can you show me all available dashboards in the system? ``` ``` Create a new dataset with name {dataset_name} and connection string {connection_string}. ``` ``` Can you add new rows to table {table_name} in dataset {dataset_id}? ``` ``` Can you clone report {report_id} in workspace group {group_id} with new name {new_report_name}? ``` ## Related Resources * [Understanding Model Context Protocol (MCP)](/guides/deploy/mcp) * [Power BI API Documentation](https://learn.microsoft.com/en-us/rest/api/power-bi/) # Recall.ai Source: https://docs.xpander.ai/connectors/recall-ai Learn how to integrate AI agents with Recall.ai using xpander.ai. Create intelligent, real-time meeting assistants that can join calls across Zoom, Google Meet, and Microsoft Teams, transcribe conversations live. ## About Recall.ai Recall.ai is a developer-focused platform that offers a universal API for accessing and processing data from virtual meetings across platforms like Zoom, Google Meet, Microsoft Teams, Webex, Slack Huddles, and GoTo Meeting. It enables developers to integrate real-time and post-meeting data—such as audio, video, transcripts, and metadata—into their applications with minimal effort. Key features include: * **Unified API Across Platforms**: Simplifies integration by providing a single API to access data from various video conferencing platforms, even those without official APIs, requiring only the meeting URL. * **Real-Time Data Access**: Offers real-time audio and video streams with low latency (approximately 200ms), enabling functionalities like live transcription and speaker identification. * **Comprehensive Metadata Retrieval**: Provides detailed meeting metadata, including participant names, roles, join times, speaking durations, and screen-sharing events. * **Rapid Deployment**: Allows developers to deploy meeting bots and integrate functionalities in days rather than months, significantly reducing development time and resources. ## Authentication Options Below are possible authentication options you can choose: ### Generate a Recall.ai API Key 1. Sign in to your Recall dashboard, where you can manage your API tokens: * [(US) us-east-1](https://us-east-1.recall.ai/auth/login/?next=/dashboard/api-keys) * [(Pay-as-you-go) us-west-2](https://us-west-2.recall.ai/auth/login/?next=/dashboard/api-keys) * [(EU) eu-central-1](https://eu-central-1.recall.ai/auth/login/?next=/dashboard/api-keys) * [(JP) ap-northeast-1](https://ap-northeast-1.recall.ai/auth/login/?next=/dashboard/api-keys) 2. Create a new API token and copy it to your clipboard. ### Integrate Recall.ai into xpander.ai 1. Go to the **Connectors** section in the sidebar of your xpander.ai dashboard. 2. Select **Recall.ai** from the available integrations. 3. Click **Enable**. 4. Enter a **connector name**, e.g., "xpander-recallai". 5. Select **Integration User** as the authentication mode. 6. Select **API Key** as the authentication method. 7. Paste the Recall.ai API key into the provided field using the following format:\ `Token [YOUR_API_KEY]` 8. Choose **Custom** as the **Auth Type**. 9. Under **Custom header name**, type `Authorization`. 10. Save the configuration. Img 1 ## Integration of Recall.ai into AI Agent Once you've configured your Recall.ai account with the authentication option(s) described above, you can integrate it into your AI agent with xpander.ai: 1. In your xpander.ai dashboard, go to the **Agent Configuration** tab and select **Tools**, then click **Add Tools**. 2. Select **Connectors**. 3. Choose **Recall.ai** with the same **connector name** you configured in the previous section (e.g., xpander-recallai). 4. Select the available Recall.ai operations that suit your use case. Img 2 ## Expose Recall.ai as MCP Server Alternatively, you can also expose your Recall.ai account as an MCP server. To do so: 1. Go to the **Connectors** section in the sidebar of your xpander.ai dashboard. 2. Select **Recall.ai** with the same **connector name** you configured in the previous section (e.g., xpander-recallai). 3. Click **MCP Configuration**. 4. Enter the MCP configuration into the appropriate settings of the client app you want to use (e.g., Cursor, Windsurf, Claude Desktop, etc.). Img 3 ## AI Agent Recall.ai Prompt Library Below are possible prompts or use cases you can try after integrating Recall.ai into your xpander AI agent: ``` Could you retrieve the transcript from yesterday's client presentation recording? ``` ``` Could you delete the recording from our internal strategy meeting on {date}? ``` ``` Would it be possible to get the bot intelligence analysis for our {customer_interview} from {day}? ``` ``` Can you schedule a bot to record our team meeting on {day} with {team_name}? ``` ## Related Resources * [Understanding Model Context Protocol (MCP)](/guides/deploy/mcp) * [Recall.ai API Documentation](https://docs.recall.ai/reference/authentication) # Amazon Redshift Source: https://docs.xpander.ai/connectors/redshift Connect Amazon Redshift to xpander using IAM authentication Connect Amazon Redshift to xpander using IAM authentication. This guide covers connecting a private Redshift cluster accessible only from the Kubernetes cluster — no public access required. For self-hosted deployments, ensure the [AWS Operator](/self-hosted/aws-operator) is configured with IAM role and Pod Identity before following this guide. ## Prerequisites * A running xpander environment (cloud or [self-hosted](/self-hosted/index)) * Your xpander Organization ID * AWS CLI access to the account *** ## 1. Create Redshift Subnet Group Place Redshift in the same private subnets as your EKS nodes: ```bash theme={"dark"} aws redshift create-cluster-subnet-group \ --cluster-subnet-group-name xpander-redshift \ --description "xpander Redshift private subnets" \ --subnet-ids \ --region --profile ``` ## 2. Create Security Group Lock access to Redshift port 5439 — only allow traffic from the EKS cluster security group: ```bash theme={"dark"} # Get the EKS cluster security group EKS_SG=$(aws eks describe-cluster --name \ --region --profile \ --query 'cluster.resourcesVpcConfig.clusterSecurityGroupId' --output text) # Create Redshift security group REDSHIFT_SG=$(aws ec2 create-security-group \ --group-name xpander-redshift-sg \ --description "Redshift SG - EKS cluster access only" \ --vpc-id \ --region --profile \ --query 'GroupId' --output text) # Allow port 5439 only from EKS aws ec2 authorize-security-group-ingress \ --group-id $REDSHIFT_SG \ --protocol tcp --port 5439 \ --source-group $EKS_SG \ --region --profile ``` ## 3. Create Redshift Cluster ```bash theme={"dark"} aws redshift create-cluster \ --cluster-identifier xpander-redshift \ --cluster-type single-node \ --node-type ra3.xlplus \ --master-username xpander_admin \ --master-user-password '' \ --db-name xpander_demo \ --cluster-subnet-group-name xpander-redshift \ --vpc-security-group-ids $REDSHIFT_SG \ --no-publicly-accessible \ --encrypted \ --region --profile ``` Wait for the cluster (\~5-10 minutes): ```bash theme={"dark"} aws redshift wait cluster-available \ --cluster-identifier xpander-redshift \ --region --profile ``` **Node types:** `dc2.large` ($0.25-0.33/hr) is cheapest but not available in all regions. Use `ra3.xlplus` ($1.08-1.20/hr) as fallback. Check availability: ```bash theme={"dark"} aws redshift describe-orderable-cluster-options \ --region --profile \ --query 'OrderableClusterOptions[*].NodeType' --output json | \ python3 -c "import json,sys; print(sorted(set(json.load(sys.stdin))))" ``` Get the endpoint: ```bash theme={"dark"} aws redshift describe-clusters \ --cluster-identifier xpander-redshift \ --region --profile \ --query 'Clusters[0].Endpoint.{Address:Address,Port:Port}' --output table ``` ## 4. Create IAM Role The IAM role needs three trust principals: | Principal | Purpose | | -------------------------------------------------------- | -------------------------------------------------------------------------------- | | `pods.eks.amazonaws.com` | EKS Pod Identity — lets xpander pods assume the role | | `arn:aws:iam:::root` | Cross-account assume with External ID for the xpander platform | | `arn:aws:iam:::role/xpander-redshift-access` | Self-assume — the AI gateway re-assumes its own role to get Redshift credentials | ```bash theme={"dark"} cat < /tmp/redshift-trust.json { "Version": "2012-10-17", "Statement": [ { "Sid": "PodIdentity", "Effect": "Allow", "Principal": { "Service": "pods.eks.amazonaws.com" }, "Action": ["sts:AssumeRole", "sts:TagSession"] }, { "Sid": "CrossAccountWithExternalId", "Effect": "Allow", "Principal": { "AWS": "arn:aws:iam:::root" }, "Action": ["sts:AssumeRole", "sts:TagSession"], "Condition": { "StringEquals": { "sts:ExternalId": "" } } }, { "Sid": "SelfAssume", "Effect": "Allow", "Principal": { "AWS": "arn:aws:iam:::role/xpander-redshift-access" }, "Action": ["sts:AssumeRole", "sts:TagSession"] } ] } TRUST aws iam create-role \ --role-name xpander-redshift-access \ --assume-role-policy-document file:///tmp/redshift-trust.json \ --profile ``` The `SelfAssume` statement must **NOT** have an `ExternalId` condition. The AI gateway's internal code calls `sts:AssumeRole` on its own role without passing an external ID. If this statement is missing or has a condition, you'll get `AccessDenied` errors. ## 5. Attach Permission Policies The role needs three permission policies. ### Redshift Credential Access ```bash theme={"dark"} aws iam put-role-policy \ --role-name xpander-redshift-access \ --policy-name RedshiftCredentials \ --policy-document '{ "Version": "2012-10-17", "Statement": [{ "Effect": "Allow", "Action": [ "redshift:GetClusterCredentials", "redshift:GetClusterCredentialsWithIAM", "redshift:DescribeClusters" ], "Resource": [ "arn:aws:redshift:::cluster:", "arn:aws:redshift:::dbname:/", "arn:aws:redshift:::dbuser:/*" ] }] }' \ --profile ``` ### Redshift Data API ```bash theme={"dark"} aws iam put-role-policy \ --role-name xpander-redshift-access \ --policy-name RedshiftDataAPI \ --policy-document '{ "Version": "2012-10-17", "Statement": [{ "Effect": "Allow", "Action": [ "redshift-data:ExecuteStatement", "redshift-data:GetStatementResult", "redshift-data:DescribeStatement", "redshift-data:ListStatements", "redshift-data:CancelStatement", "redshift-data:BatchExecuteStatement", "redshift-data:ListDatabases", "redshift-data:ListSchemas", "redshift-data:ListTables", "redshift-data:DescribeTable" ], "Resource": "*" }] }' \ --profile ``` ### Self-Assume and Session Tagging ```bash theme={"dark"} aws iam put-role-policy \ --role-name xpander-redshift-access \ --policy-name SelfAssumeAndTagSession \ --policy-document '{ "Version": "2012-10-17", "Statement": [{ "Effect": "Allow", "Action": ["sts:AssumeRole", "sts:TagSession"], "Resource": "arn:aws:iam:::role/xpander-redshift-access" }] }' \ --profile ``` ## 6. Create IAM-Mapped Redshift User The username `IAMR:` is a Redshift convention that maps the IAM role to a database user. ```bash theme={"dark"} kubectl run redshift-iam-setup --restart=Never --image=postgres:15-alpine -n xpander \ --env="PGPASSWORD=" \ --command -- psql -h -p 5439 -U -d -c " CREATE USER \"IAMR:xpander-redshift-access\" PASSWORD DISABLE; GRANT SELECT ON ALL TABLES IN SCHEMA public TO \"IAMR:xpander-redshift-access\"; ALTER DEFAULT PRIVILEGES IN SCHEMA public GRANT SELECT ON TABLES TO \"IAMR:xpander-redshift-access\";" sleep 15 && kubectl logs redshift-iam-setup -n xpander kubectl delete pod redshift-iam-setup -n xpander ``` ## 7. Associate Role with Service Account ```bash theme={"dark"} aws eks create-pod-identity-association \ --cluster-name \ --namespace xpander \ --service-account xpander \ --role-arn arn:aws:iam:::role/xpander-redshift-access \ --region --profile ``` ## 8. Configure in xpander UI In the xpander connector configuration, set: | Field | Value | | -------------------- | ----------------------------------------------------------- | | **ClusterNamePath** | Your Redshift cluster identifier (e.g., `xpander-redshift`) | | **DatabaseNamePath** | Your database name (e.g., `xpander_demo`) | | **CatalogNamePath** | `pg_catalog.svv_all_columns` (recommended) | | **IAM Role ARN** | `arn:aws:iam:::role/xpander-redshift-access` | | **Region** | Your AWS region (e.g., `us-west-1`) | | **Auth Method** | IAM | ## 9. Verify Connection Ask your xpander agent to validate the Redshift connection. Expected result: all checks pass (path config, database, target, AWS credentials, Data API client, auth method, query execution). *** ## Troubleshooting Add `sts:TagSession` to both the trust policy AND as a permission policy on the role. The AI gateway re-assumes its own role internally. The trust policy needs a `SelfAssume` statement for the role's own ARN **without** an `ExternalId` condition. Also add `sts:AssumeRole` as a permission policy. Add the Redshift Data API permissions policy (see [step 5](#5-attach-permission-policies)). Check the Redshift security group allows port 5439 from the EKS cluster security group. The connector path parameters (`ClusterNamePath`, `DatabaseNamePath`, `CatalogNamePath`) must be configured in the xpander UI with the correct values. # Slack Source: https://docs.xpander.ai/connectors/slack Learn how to integrate AI agents with Slack using xpander.ai. Create seamless workflows that automate repetitive tasks, provide instant insights, and enhance team collaboration by leveraging AI-powered assistants directly within your Slack channels and conversations. **Looking for Slack-native AI agents?** Check out our [Slack Agents](/guides/deploy/slack) feature for the fastest way to deploy AI agents directly to Slack with Smart Engage™ technology, built-in OAuth, and zero infrastructure setup. ## About Slack Slack is a cloud-based communication and collaboration platform designed to streamline team interactions, replacing traditional email chains and enhancing productivity. Key features include: * **Channels**: Organize conversations by topics, projects, or teams. Channels can be public (open to all members) or private (restricted access). * **Direct Messaging**: Send private messages to individuals or groups for more focused discussions. * **Huddles**: Initiate quick audio or video calls within channels or direct messages to facilitate real-time conversations. * **File Sharing**: Easily share documents, images, and other files within conversations, with the ability to integrate with services like Google Drive and Dropbox. * **Integrations**: Connect with over 2,400 third-party applications, including Google Calendar, Asana, and Salesforce, to centralize your workflow. * **Searchable History**: Access and search through past messages and files, ensuring important information is always retrievable. * **Automation**: Utilize tools like Workflow Builder to automate repetitive tasks and processes, enhancing efficiency. ## Authentication Options Below are possible authentication options you can choose: The simplest way to connect Slack is by using xpander.ai's built-in authentication: 1. Go to the **Connectors** section in the sidebar of your xpander.ai dashboard. 2. Select **Slack** from the available integrations. 3. Click **Sign in with Slack**. 4. Grant xpander.ai permission to access specific channels in your Slack workspace. 5. Your Slack integration is now ready to use. ### Generate a Slack API Key 1. Log in to [Slack Apps](https://api.slack.com/apps). 2. Click **Create an App**, then select **From scratch**. 3. Give your app a name, and select the Slack workspace you want to develop it in. Img 1 4. After clicking **Create App**, go to the **OAuth & Permissions** section in the sidebar. Img 2 5. Under the **Scopes** section, in **Bot Token Scopes**, click **Add an OAuth Scope** and select the permissions your app needs.\ You can browse all available scopes [here](https://api.slack.com/scopes). Img 3 6. Still in **OAuth & Permissions**, scroll to **OAuth Tokens** and click **Install to \**. Img 4 7. After installation, your Slack access token will be displayed—make sure to save it securely. Img 5 ### Integrate Slack into xpander.ai 1. Go to the **Connectors** section in the sidebar of your xpander.ai dashboard. 2. Select **Slack** from the available integrations. 3. Click **Other auth options**. 4. Enter a **connector name**, e.g., "xpander-slack". 5. Choose **Integration User** as the authentication mode. 6. Select **API Key** as the authentication method. 7. Paste the Slack access token into the provided field. 8. Set the **Auth Type** to **Bearer**. 9. Save the configuration. Img 6 ## Integration of Slack into AI Agent Once you've configured your Slack account with the authentication option(s) described above, you can integrate it into your AI agent with xpander.ai: 1. In your xpander.ai dashboard, go to the **Agent Configuration** tab and select **Tools**, then click **Add Tools**. 2. Select **Connectors**. 3. Choose **Slack** with the same **connector name** you configured in the previous section (e.g., xpander-slack). 4. Select the available Slack operations that suit your use case. Img 7 ## Expose Slack as MCP Server Alternatively, you can also expose your Slack account as an MCP server. To do so: 1. Go to the **Connectors** section in the sidebar of your xpander.ai dashboard. 2. Select **Slack** with the same **connector name** you configured in the previous section (e.g., xpander-slack). 3. Click **MCP Configuration**. 4. Enter the MCP configuration into the appropriate settings of the client app you want to use (e.g., Cursor, Windsurf, Claude Desktop, etc.). Img 8 ## AI Agent Slack Prompt Library Below are possible prompts or use cases you can try after integrating Slack into your xpander AI agent: ``` Could you invite {user_name} to the #marketing-team channel? ``` ``` Can you create a new private channel called {channel_name} for our upcoming project? ``` ``` Would you schedule a reminder message about the {event_name} for next Friday at 3pm? ``` ``` Can you share the {document_name} file with the #product-team channel? ``` ## Related Resources * [Understanding Model Context Protocol (MCP)](/guides/deploy/mcp) * [Slack API Documentation](https://api.slack.com/quickstart) # Snowflake Source: https://docs.xpander.ai/connectors/snowflake Learn how to integrate AI agents with Snowflake using xpander.ai. Create intelligent agents that can query your Snowflake data warehouse, retrieve analytics insights, explore databases and schemas, and automate data-driven workflows. ## About Snowflake **Snowflake** is a cloud-based data platform designed for modern analytics, AI applications, and large-scale data engineering. It enables developers, data teams, and intelligent agents to store, process, and analyze massive datasets using a unified, fully cloud-native data warehouse architecture. Snowflake offers advanced capabilities such as data sharing, secure collaboration, and workload isolation through virtual warehouses, along with native support for modern data engineering and machine learning pipelines. These features allow teams to run concurrent analytical queries, ingest streaming or batch data, and securely share datasets across organizations, all while maintaining high performance and scalability. ## Authentication Options Below are possible authentication options you can choose: ### Generate a Snowflake Programmatic Access Token 1. Log in to your [Snowflake account](https://app.snowflake.com/). 2. Select **Governance & security**, then click **Users & roles**. Img 1 3. Select a user to open the user’s page, scroll down to the **Programmatic access tokens** section, and click **Generate token** to open the **New programmatic access token** dialog. Img 2 4. Enter a name for the new programmatic access token, set the expiry period and role, then click **Generate** to create the token. 5. A new dialog will appear with the created token. Click **Copy to clipboard and close** to copy the generated token and store it somewhere safe. Img 3 If your Snowflake user does not have a network policy, you’ll need to create one to proceed. Follow [Snowflake’s official instructions](https://docs.snowflake.com/en/guides/network-policies) to create a new network policy. Alternatively, you can grant temporary access for your programmatic access token. To do that: 1. Click the ellipsis icon next to the programmatic access token 2. Select **Bypass requirement for network policy** in the dropdown that appears to open the **Bypass Network Policy Requirement** dialog. Img 4 3. Specify a **Bypass window** and click **Grant access** to grant your programmatic access token temporary access. Img 5 ### Integrate Snowflake into xpander.ai 1. Go to the **Agentic Connectors** section in the sidebar of your xpander.ai dashboard. 2. Select **Snowflake** from the available integrations. 3. Click **+ Create new connection**. 4. Enter a **connector name** as desired, e.g., "xpander-snowflake". 5. Paste your Snowflake programmatic access token into the provided **API Key** field. 6. Copy the **base URL** from your Snowflake web console, e.g., `https://.snowflakecomputing.com`, and paste it into the **Interface specific settings** field. 7. Save the configuration. Img 6 ## Integration of Snowflake into an AI Agent Once you’ve configured your Snowflake connector with the authentication option(s) described above, you can integrate it into your AI agent with xpander.ai: 1. In your xpander.ai dashboard, navigate to the **Agents** page, select an agent and click **Edit** on the agent page to open the **Agent Configuration** tab. 2. Select **Tools**, then click **Add Tools**. 3. Select **Connectors**. 4. Choose **Snowflake** with the same **connector name** you configured in the previous section (e.g., xpander-snowflake). 5. Select the available Snowflake operations that suit your use case. To grant your agent database management capabilities, enable the following operations. * **Submit SQL Statements For Execution** * **Get Statement Status by Handle** * **Cancel Statement by Handle** Img 7 ## AI Agent Snowflake Prompt Library Below are possible prompts or use cases you can try after integrating Snowflake into your xpander.ai AI agent: ``` List my databases. ``` ``` Add a to my database. ``` ``` Add a with the following columns to the schema belonging to the database. ``` ``` Return all rows in the table in the schema belonging to the database. ``` Gif 1 ## Related Resources * [Using Tools & Connectors in the xpander.ai platform](/guides/agents/tools-connectors) * [Snowflake Documentation](https://docs.snowflake.com/en/index) # Statuspage Source: https://docs.xpander.ai/connectors/statuspage Learn how to integrate AI agents with StatusPage using xpander.ai. Create automated workflows that detect incidents, trigger real-time updates, and communicate seamlessly with users through your customized status page. ## About Statuspage Statuspage is a communication tool developed by Atlassian that enables organizations to provide real-time updates on the status of their services. It is designed to enhance transparency and trust by keeping users informed during incidents, outages, or scheduled maintenance. Statuspage key features: * **Incident Communication**: Allows teams to post timely updates about service disruptions, helping to reduce support inquiries and keep users informed. * **Customizable Status Pages**: Offers the ability to create public, private, or audience-specific status pages, ensuring that the right information reaches the appropriate audience. Atlassian Support * **Notifications**: Supports multiple notification channels, including email, SMS, Slack, and Microsoft Teams, to alert subscribers about incidents and updates. * **Third-Party Integrations**: Integrates with various monitoring and alerting tools such as DataDog, New Relic, Pingdom, Opsgenie, and PagerDuty, enabling automated status updates based on system metrics. ## Authentication Options Below are possible authentication options you can choose: ### Generate a StatusPage API Key 1. Log in to your [StatusPage account](https://manage.statuspage.io/login). 2. Click on your profile icon in the top-right corner, then select **API info**. Img 1 3. Click **Create key**, give your key a name, and your API key will be displayed. Img 2 ### Integrate StatusPage into xpander.ai 1. In your xpander.ai dashboard, go to the **Connectors** section in the sidebar. 2. Select **StatusPage** from the available integrations. 3. Click **Enable**. 4. Enter a **connector name**, e.g., "xpander-statuspage". 5. Select **Integration User** for the authentication mode. 6. Choose **API Key** as the authentication method. 7. Paste your StatusPage API key into the provided field. 8. Set the **Auth Type** to **Basic**. 9. Save the configuration. Img 3 ## Integration of Statuspage into AI Agent Once you've configured your Statuspage account with the authentication option(s) described above, you can integrate it into your AI agent with xpander.ai: 1. In your xpander.ai dashboard, go to the **Agent Configuration** tab and select **Tools**, then click **Add Tools**. 2. Select **Connectors**. 3. Choose **Statuspage** with the same **connector name** you configured in the previous section (e.g., xpander-statuspage). 4. Select the available Statuspage operations that suit your use case. Img 4 ## Expose Statuspage as MCP Server Alternatively, you can also expose your Statuspage account as an MCP server. To do so: 1. Go to the **Connectors** section in the sidebar of your xpander.ai dashboard. 2. Select **Statuspage** with the same **connector name** you configured in the previous section (e.g., xpander-statuspage). 3. Click **MCP Configuration**. 4. Enter the MCP configuration into the appropriate settings of the client app you want to use (e.g., Cursor, Windsurf, Claude Desktop, etc.). Img 5 ## AI Agent Statuspage Prompt Library Below are possible prompts or use cases you can try after integrating Statuspage into your xpander AI agent: ``` We need to add the latest performance metrics for our API gateway. Can you update that? ``` ``` Could you add {emailAddress} as a subscriber to the current network outage incident? ``` ``` We need to schedule maintenance for our database cluster on {date} at {time}. Can you set that up? ``` ``` Can you retrieve all current incidents affecting our services? ``` ## Related Resources * [Understanding Model Context Protocol (MCP)](/guides/deploy/mcp) * [Statuspage API Documentation](https://developer.statuspage.io/#operation/getPages) # Supabase Source: https://docs.xpander.ai/connectors/supabase Learn how to integrate AI agents with Supabase using xpander.ai. Create intelligent, data-driven applications that leverage Supabase’s real-time PostgreSQL database, authentication, and storage features. ## About Supabase Supabase is an open-source Backend-as-a-Service (BaaS) platform designed to simplify and accelerate application development by providing a suite of backend tools and services. Key features include: * **PostgreSQL Database**: Supabase provides a full PostgreSQL database with real-time capabilities, allowing developers to leverage SQL's robustness and familiarity . * **Authentication & Authorization**: Built-in user management with support for various authentication methods, including email, password, and third-party providers. * **Instant APIs**: Automatically generated RESTful and GraphQL APIs based on your database schema, facilitating rapid development. * **Edge Functions**: Serverless functions that run close to the user, enabling low-latency operations and custom backend logic. * **Realtime Subscriptions**: Listen to database changes in real-time, enabling dynamic and responsive applications. * **Storage**: Manage and serve large files, such as images and videos, with built-in storage solutions. * **Vector Embeddings**: Support for AI and machine learning workloads through vector embeddings, useful for applications like semantic search. ## Authentication Options Below are possible authentication options you can choose: ### Generate a Supabase API Key 1. Log in to your [Supabase account](https://supabase.com). 2. Click your profile icon at the top right of the dashboard, then select **Account preferences**. Img 1 3. In the sidebar, click **Access tokens**, then click **Generate new token**. Img 2 4. Give the token a name and click **Generate token**. 5. Your access token will be shown—copy it somewhere safe. ### Integrate Supabase into xpander.ai 1. Go to the **Connectors** section in the sidebar of your xpander.ai dashboard. 2. Select **Supabase** from the available integrations. 3. Click **Enable**. 4. Enter a **connector name**, e.g., "xpander-supabase". 5. Choose **Integration User** as the authentication mode. 6. Select **API Key** as the authentication method. 7. Paste the Supabase access token into the provided field. 8. Set the **Auth Type** to **Bearer**. 9. Save the configuration. Img 3 ## Integration of Supabase into AI Agent Once you've configured your Supabase account with the authentication option(s) described above, you can integrate it into your AI agent with xpander.ai: 1. In your xpander.ai dashboard, go to the **Agent Configuration** tab and select **Tools**, then click **Add Tools**. 2. Select **Connectors**. 3. Choose **Supabase** with the same **connector name** you configured in the previous section (e.g., xpander-supabase). 4. Select the available Supabase operations that suit your use case. Img 4 ## Expose Supabase as MCP Server Alternatively, you can also expose your Supabase account as an MCP server. To do so: 1. Go to the **Connectors** section in the sidebar of your xpander.ai dashboard. 2. Select **Supabase** with the same **connector name** you configured in the previous section (e.g., xpander-supabase). 3. Click **MCP Configuration**. 4. Enter the MCP configuration into the appropriate settings of the client app you want to use (e.g., Cursor, Windsurf, Claude Desktop, etc.). Img 5 ## AI Agent Supabase Prompt Library Below are possible prompts or use cases you can try after integrating Supabase into your xpander AI agent: ``` Could you create a new branch called {branch_name} for my {project_name} project? ``` ``` How do I delete the API key with ID {api_key_id} from my {project_name} project? ``` ``` How can I update the PostgreSQL configuration for my {project_name} to increase the maximum connections? ``` ``` Could you disable the read-only mode for my {project_name} project? ``` ## Related Resources * [Understanding Model Context Protocol (MCP)](/guides/deploy/mcp) * [Supabase API Documentation](https://supabase.com/docs/guides/api) # Supabase Database Source: https://docs.xpander.ai/connectors/supabase-database Learn how to integrate AI agents with Supabase Database using xpander.ai. Create intelligent applications where agents can query, update, and respond to real-time data events using Supabase’s PostgreSQL backend. ## About Supabase Database Supabase database is a fully managed PostgreSQL instance enriched with real-time capabilities and developer-friendly tools, making it a robust solution for modern application development. Key features include: * **Full PostgreSQL Access**: Each Supabase project includes a dedicated PostgreSQL database, providing developers with the full power and flexibility of Postgres, including advanced data types, indexing, and SQL support. * **Realtime Capabilities**: Supabase extends PostgreSQL with real-time functionality using its Realtime Server. This allows applications to listen to database changes (INSERT, UPDATE, DELETE) and respond instantly, enabling features like live dashboards and collaborative tools. * **Row Level Security (RLS)**: Supabase leverages PostgreSQL's RLS to provide fine-grained access control, ensuring that users can only access data they're authorized to see. * **Built-in Table Editor**: The Supabase Dashboard offers a user-friendly table editor, allowing developers to create and manage tables without writing SQL, making database management more accessible. * **Database Backups**: Supabase automatically manages database backups, providing peace of mind and data safety without manual intervention. * **Extensions Support**: Developers can enhance their databases by enabling PostgreSQL extensions directly from the Supabase Dashboard, adding functionalities like full-text search, GIS support, and more. ## Authentication Options Below are possible authentication options you can choose: ### Generate a Supabase Database API Key 1. Log in to your [Supabase account](https://supabase.com) and open your desired project. 2. Navigate to **Project Settings** in the sidebar, then click on **Data API**. Img 1 3. In the **Project API Keys** section, you'll see your project API key—copy it somewhere safe. 4. Next, you'll also need the project ID to use the Supabase Database API. To find it, go to **General** in the sidebar. 5. Under **General settings**, you'll see your project ID—save this ID for later use. Img 2 ### Integrate Supabase Database into xpander.ai 1. Go to the **Connectors** section in the sidebar of your xpander.ai dashboard. 2. Select **Supabase Database API** from the available integrations. 3. Click **Enable**. 4. Enter a **connector name**, e.g., "xpander-supabase-database". 5. Choose **Integration User** as the authentication mode. 6. Select **API Key** as the authentication method. 7. Paste the Supabase project API key into the provided field. 8. Set the **Auth Type** to **Custom**. 9. In the **Custom header name** field, type: `apikey` 10. In the **Interface specific settings** section, enter your Supabase project ID in the following format:\ `https://.supabase.co/rest/v1` 11. Save the configuration. Img 3 ## Integration of Supabase Database into AI Agent Once you've configured your Supabase Database account with the authentication option(s) described above, you can integrate it into your AI agent with xpander.ai: 1. In your xpander.ai dashboard, go to the **Agent Configuration** tab and select **Tools**, then click **Add Tools**. 2. Select **Connectors**. 3. Choose **Supabase Database** with the same **connector name** you configured in the previous section (e.g., xpander-supabase-database). 4. Select the available Datadog operations that suit your use case. Img 4 ## Expose Supabase Database as MCP Server Alternatively, you can also expose your Supabase Database account as an MCP server. To do so: 1. Go to the **Connectors** section in the sidebar of your xpander.ai dashboard. 2. Select **Supabase Database** with the same **connector name** you configured in the previous section (e.g., xpander-supabasse-database). 3. Click **MCP Configuration**. 4. Enter the MCP configuration into the appropriate settings of the client app you want to use (e.g., Cursor, Windsurf, Claude Desktop, etc.). Img 5 ## AI Agent Supabase Database Prompt Library Below are possible prompts or use cases you can try after integrating Supabase Database into your xpander AI agent: ``` Could you retrieve all active projects from our database? ``` ``` Can you delete the product listing for {product_name} that was discontinued? ``` ``` Can you retrieve all payments made by customer {customer_id} in the last month? ``` ``` Can you remove all tasks assigned to {employee_name} who is no longer with the company? ``` ## Related Resources * [Understanding Model Context Protocol (MCP)](/guides/deploy/mcp) * [Supabase API Documentation](https://supabase.com/docs/guides/api) # Tableau Source: https://docs.xpander.ai/connectors/tableau Learn how to integrate AI agents with Tableau using xpander.ai. Create intelligent dashboards that deliver contextual insights, automate data-driven decisions, and enable natural language interactions for a seamless analytics experience. ## About Tableau Tableau is a visual analytics platform that empowers individuals and organizations to explore and understand data through interactive visualizations. Key features include: * **Interactive Data Visualization**: Drag-and-drop interface to create dashboards, charts, graphs, and maps without coding. * **Wide Data Connectivity**: Connects to multiple data sources such as Relational databases (MySQL, PostgreSQL, SQL Server, Oracle), cloud services (Google BigQuery, AWS Redshift, Snowflake), spreadsheets (Excel, CSV, Google Sheets), and web connectors (APIs). * **Geospatial & Mapping Capabilities**: Built-in geocoding and mapping for creating geographic visualizations. * **Natural Language & AI Features**: Natural language queries for instant insights and AI-driven explanations of outliers and patterns. * **Dashboard Interactivity**: Filters, actions, and parameters for interactive dashboards. ## Authentication Options Below are possible authentication options you can choose: ### Generate a Tableau API Token 1. Log in to your [Tableau Cloud or Tableau Server account](https://www.tableau.com/tableau-login-hub). 2. In the sidebar of your account dashboard, click the gear icon. Under the **General** tab, find the **Personal Access Tokens** section. 3. Check the box for **Enable personal access tokens**, then click **Save**. Img 1 4. Click your profile icon at the top right of the dashboard, then select **My Account Settings**. 5. In the **Settings** tab, locate the **Personal Access Tokens** section. Enter a name for your token and click **Create token**. Img 2 6. Copy your personal access token and save it securely before closing the dialog box. 7. Obtain an authentication token by executing the following request: ``` curl -X POST "https://{YOUR_SERVER_NAME}/api/3.26/auth/signin" \ -H "Content-Type: application/json" \ -d '{ "credentials": { "personalAccessTokenName": "YOUR_PAT_NAME", "personalAccessTokenSecret": "YOUR_PAT_SECRET", "site": { "contentUrl": "YOUR_SITE_NAME" } } }' ``` Replace **personalAccessTokenName** and **personalAccessTokenSecret** with the token name and secret you obtained above. You can find your server name and site name in your Tableau URL. For example, if your URL is: [https://dub01.online.tableau.com/#/site/xpandersandbox2-577b145t/](https://dub01.online.tableau.com/#/site/xpandersandbox2-577b145t/), then: * Server name: dub01.online.tableau.com * Site name: xpandersandbox2-577b145t 8. Save the authentication token you obtained somewhere safe. ### Integrate Tableau into xpander.ai 1. In your xpander.ai dashboard, go to the **Connectors** section in the sidebar. 2. Select **Tableau** from the available integrations. 3. Click **Enable**. 4. Enter a **connector name**, e.g., "xpander-tableau". 5. Choose **Integration User** as the authentication mode. 6. Select **API Key** as the authentication method. 7. Paste your Tableau authentication token into the provided field. 8. Set the **Auth Type** to **Custom**. 9. Write **X-Tableau-Auth** as the custom header name. 10. Under **Interface specific settings**, enter the base URL: `https://{server}/api/{api-version}`. Replace `{server}` with the server name of your Tableau account and `{api-version}` with the API version, such as 3.26. 11. Save the configuration. Img 3 ## Integration of Tableau into AI Agent Once you've configured your Tableau account with the authentication option(s) described above, you can integrate it into your AI agent with xpander.ai: 1. In your xpander.ai dashboard, go to the **Agent Configuration** tab and select **Tools**, then click **Add Tools**. 2. Select **Connectors**. 3. Choose **Tableau** with the same **connector name** you configured in the previous section (e.g., xpander-tableau). 4. Select the available Tableau operations that suit your use case. Img 4 ## Expose Tableau as MCP Server Alternatively, you can also expose your Tableau account as an MCP server. To do so: 1. Go to the **Connectors** section in the sidebar of your xpander.ai dashboard. 2. Select **Tableau** with the same **connector name** you configured in the previous section (e.g., xpander-tableau). 3. Click **MCP Configuration**. 4. Enter the MCP configuration into the appropriate settings of the client app you want to use (e.g., Cursor, Windsurf, Claude Desktop, etc.). Img 5 ## AI Agent Tableau Prompt Library Below are possible prompts or use cases you can try after integrating Tableau into your xpander AI agent: ``` Can you get me the usage statistics for this {content_type} with ID {content_item_id} so I can analyze how frequently it's being accessed? ``` ``` Can you show me all the sites available in our Tableau environment and their configuration details? ``` ``` Can you retrieve the current data for metric {metric_id} in site {site_id} to analyze recent performance trends? ``` ``` Can you remove the default user permission for user {user_id} from data sources in project {project_id} within site {site_id}? ``` ## Related Resources * [Understanding Model Context Protocol (MCP)](/guides/deploy/mcp) * [Tableau API Documentation](https://help.tableau.com/current/api/rest_api/en-us/REST/rest_api.htm) # Tomorrow.io Source: https://docs.xpander.ai/connectors/tomorrow-io Learn how to integrate AI agents with Tomorrow.io using xpander.ai. Create intelligent, weather-aware systems that dynamically adjust operations according to real-time climate data. ## About Tomorrow\.io Tomorrow\.io is a weather and climate intelligence company that offers advanced forecasting solutions for businesses, governments, and individuals. Tomorrow\.io provides a customizable platform that delivers hyperlocal forecasts, real-time alerts, and predictive analytics. This enables users to make informed decisions based on weather conditions, which improves operational efficiency and safety. ## Authentication Options Below are possible authentication options you can choose: ### Generate Tomorrow\.io API Key 1. Log in to your [Tomorrow.io account](https://www.tomorrow.io/). 2. Once you're logged in, you'll see your API key in your main dashboard.\\ Img 1 ### Integrate Tomorrow\.io into Xpander.ai 1. Go to the **Connectors** section in the sidebar of your xpander.ai dashboard. 2. Select **Tomorrow\.io** from the available integrations. 3. Click **Enable**. 4. Fill in the **connector name** as desired, e.g., "xpander-tomorrow". 5. Choose **Integration user** as the authentication mode. 6. Choose **API Key** as the authentication method. 7. Copy and paste your Tomorrow\.io API key into the provided field. 8. Choose **Custom** as the **auth type**. 9. Enter **apikey** as the **Custom header name**. 10. Enter **[https://api.tomorrow.io/v4/](https://api.tomorrow.io/v4/)** as the base URL in the **Interface specific settings** section. 11. Save the configuration. Img 2 ## Integration of Tomorrow\.io into AI Agent Once you've configured your Tomorrow\.io account with the authentication option(s) described above, you can integrate it into your AI agent with xpander.ai: 1. In your xpander.ai dashboard, go to the **Agent Configuration** tab and select **Tools**, then click **Add Tools**. 2. Select **Connectors**. 3. Choose **Tomorrow\.io** with the same **connector name** you configured in the previous section (e.g., xpander-tomorrow). 4. Select the available Tomorrow\.io operations that suit your use case. Img 3 ## Expose Tomorrow\.io as MCP Server Alternatively, you can also expose your Tomorrow\.io account as an MCP server. To do so: 1. Go to the **Connectors** section in the sidebar of your xpander.ai dashboard. 2. Select **Tomorrow\.io** with the same **connector name** you configured in the previous section (e.g., xpander-tomorrow). 3. Click **MCP Configuration**. 4. Enter the MCP configuration into the appropriate settings of the client app you want to use (e.g., Cursor, Windsurf, Claude Desktop, etc.). Img 4 ## AI Agent Tomorrow\.io Prompt Library Below are possible prompts or use cases you can try after integrating Tomorrow\.io into your xpander AI agent: ``` What's the weather forecast for {location} this weekend? ``` ``` Will there be any severe weather events in {location} tomorrow? ``` ``` What is the air quality index in {location} right now? ``` ``` Is there a risk of flooding in {location} this week? ``` ## Related Resources * [Understanding Model Context Protocol (MCP)](/guides/deploy/mcp) * [Tomorrow.io API Documentation](https://docs.tomorrow.io/) # Twilio Source: https://docs.xpander.ai/connectors/twilio Learn how to integrate AI agents with Twilio using xpander.ai. Create intelligent communication workflows that can autonomously handle customer interactions via SMS, voice, or WhatsApp—powered by real-time AI decision-making. ## About Twilio Twilio is a cloud communications platform that allows developers and businesses to programmatically make and receive phone calls, send and receive text messages (SMS), and perform other communication functions using its web service APIs. Key Features of Twilio: * **Programmable Messaging**: SMS, MMS, WhatsApp messages * **Programmable Voice**: Make, receive, and control phone calls * **Email Services**: Via Twilio SendGrid for transactional and marketing emails * **Video**: Real-time video capabilities for apps * **Authentication**: Two-factor authentication and phone number verification * **Flex**: A customizable cloud-based contact center platform ## Authentication Options Below are possible authentication options you can choose: ### Generate Twilio API Key 1. Go to your [Twilio console account](https://console.twilio.com/). 2. You can find your **Account SID** and **Auth Token** at the bottom of your account dashboard.\\ Img 1 3. Combine the Account SID and Auth Token using the following format: `account_SID:Auth_token`, and encode it using Base64. You can do this in a few ways: * Run this command: `echo -n '{account_SID}:{Auth_token}' | base64` (for Linux or macOS). * Use an [online encoder](https://www.base64encode.org/). 4. The encoded result will serve as your Twilio API key. ### Integrate Twilio into Xpander.ai 1. Go to the **Connectors** section in the sidebar of your xpander.ai dashboard. 2. Select **Twilio** from the available integrations. 3. Click **Enable**. 4. Fill in the **connector name** as desired, e.g., "xpander-twilio". 5. Choose **Integration User** as the authentication mode. 6. Choose **API Key** as the authentication method. 7. Copy and paste the encoded Twilio API key into the provided field. 8. Choose **Basic** as the **auth type**. 9. Save the configuration. Img 2 ## Integration of Twilio into AI Agent Once you've configured your Twilio account with the authentication option(s) described above, you can integrate it into your AI agent with xpander.ai: 1. In your xpander.ai dashboard, go to the **Agent Configuration** tab and select **Tools**, then click **Add Tools**. 2. Select **Connectors**. 3. Choose **Twilio** with the same **connector name** you configured in the previous section (e.g., xpander-twilio). 4. Select the available Twilio operations that suit your use case. Img 3 ## Expose Twilio as MCP Server Alternatively, you can also expose your Twilio account as an MCP server. To do so: 1. Go to the **Connectors** section in the sidebar of your xpander.ai dashboard. 2. Select **Twilio** with the same **connector name** you configured in the previous section (e.g., xpander-twilio). 3. Click **MCP Configuration**. 4. Enter the MCP configuration into the appropriate settings of the client app you want to use (e.g., Cursor, Windsurf, Claude Desktop, etc.). Img 4 ## AI Agent Twilio Prompt Library Below are possible prompts or use cases you can try after integrating Twilio into your xpander AI agent: ``` Record our conference call with {client_name} on {date}. ``` ``` Add {new_participant} to our active conference call {conference_id}. ``` ``` Generate call metrics for the {campaign_name} marketing campaign. ``` ``` Set up SMS auto-responses for support line #{phone_number}. ``` ## Related Resources * [Understanding Model Context Protocol (MCP)](/guides/deploy/mcp) * [Twilio API Documentation](https://www.twilio.com/docs) # Zapier Source: https://docs.xpander.ai/connectors/zapier Learn how to integrate AI agents with Zapier using xpander.ai. Create powerful, automated workflows that allow your AI agents to trigger actions, respond to events, and orchestrate tasks across thousands of apps. ## About Zapier Zapier is a web-based automation platform that enables users to connect various web applications and automate workflows without requiring coding skills. By linking over 5,000 apps—including Gmail, Slack, Google Sheets, Trello, and Salesforce—Zapier facilitates seamless data transfer and task automation across different services. Zapier key features: * **No-Code Automation**: Design and implement workflows without any programming knowledge. * **Extensive App Integration**: Connect with a vast array of applications to suit diverse business needs. * **Real-Time Data Syncing**: Ensure consistent and up-to-date information across platforms. * **Error Handling & Recovery**: Utilize intelligent alerts and AI-powered troubleshooting to maintain workflow integrity. * **Security & Compliance**: Benefit from SOC 2 Type II certification and GDPR compliance, ensuring data privacy and control. ## Authentication Options Below are possible authentication options you can choose: ### Generate a Zapier API Key 1. Log in to your [Zapier account](https://zapier.com/app/). 2. Connect your Zapier account with the [custom integration app](https://actions.zapier.com/custom/start/). Img 1 3. Select the apps and actions you want to integrate with Zapier. 4. Access your API key by visiting [Zapier’s action page](https://actions.zapier.com/credentials/). Img 2 ### Integrate Zapier into xpander.ai 1. In your xpander.ai dashboard, go to the **Connectors** section in the sidebar. 2. Select **Zapier** from the available integrations. 3. Click **Enable**. 4. Enter a **connector name**, e.g., "xpander-zapier". 5. Select **Integration User** for the authentication mode. 6. Choose **API Key** as the authentication method. 7. Paste your Zapier API key into the provided field. 8. Set the **Auth Type** to **Custom**. 9. In the **Custom header name** field, enter: `x-api-key`. 10. Save the configuration. Img 3 ## Integration of Zapier into AI Agent Once you've configured your Zapier account with the authentication option(s) described above, you can integrate it into your AI agent with xpander.ai: 1. In your xpander.ai dashboard, go to the **Agent Configuration** tab and select **Tools**, then click **Add Tools**. 2. Select **Connectors**. 3. Choose **Zapier** with the same **connector name** you configured in the previous section (e.g., xpander-zapier). 4. Select the available Zapier operations that suit your use case. Img 4 ## Expose Zapier as MCP Server Alternatively, you can also expose your Zapier account as an MCP server. To do so: 1. Go to the **Connectors** section in the sidebar of your xpander.ai dashboard. 2. Select **Zapier** with the same **connector name** you configured in the previous section (e.g., xpander-zapier). 3. Click **MCP Configuration**. 4. Enter the MCP configuration into the appropriate settings of the client app you want to use (e.g., Cursor, Windsurf, Claude Desktop, etc.). Img 5 ## AI Agent Zapier Prompt Library Below are possible prompts or use cases you can try after integrating Zapier into your xpander AI agent: ``` Can you create an automation that moves {file_type} files from Gmail to Dropbox? ``` ``` What options do I have for automating {social_media_platform} posts? ``` ``` How do I delete the automation that sends {notification_type} alerts to my team? ``` ``` Can you show me how to trigger an action when someone fills out my {form_provider} form? ``` ## Related Resources * [Understanding Model Context Protocol (MCP)](/guides/deploy/mcp) * [Zapier AI Action API Documentation](https://docs.zapier.com/ai-actions/intro) # Zendesk Source: https://docs.xpander.ai/connectors/zendesk Learn how to integrate AI agents with Zendesk using xpander.ai. Create seamless, automated customer interactions that enhance support efficiency, reduce response times, and deliver personalized experiences by leveraging AI-powered chatbots and smart ticket routing. ## About Zendesk Zendesk is a cloud-based customer service and engagement platform designed to help businesses manage and enhance their interactions with customers across various channels. Key features include: * **Omnichannel Support**: Zendesk consolidates customer interactions from email, live chat, voice, social media, and messaging apps into a unified ticketing system, enabling support teams to efficiently manage and resolve inquiries from multiple channels. * **AI-Powered Automation**: The platform includes AI agents and automation tools that assist in routing tickets, providing instant responses, and handling repetitive tasks, thereby improving efficiency and response times. * **Self-Service Options**: Zendesk offers features like knowledge bases, community forums, and an AI-powered Answer Bot, empowering customers to find solutions independently and reducing the volume of support tickets. * **Analytics and Reporting**: With Zendesk Explore, businesses can access real-time dashboards and detailed reports to monitor performance metrics, customer satisfaction, and team productivity, facilitating data-driven decision-making. * **Customizable Workflows**: The platform allows for the creation of custom workflows, triggers, and automations to tailor the support process to specific business needs, ensuring consistency and efficiency in customer service operations. ## Authentication Options Below are possible authentication options you can choose: ### Generate a Zendesk API Key 1. Log in to your [Zendesk account](https://www.zendesk.com/). 2. Click on your Zendesk app icon in the top-right corner and select **Admin Center**. Img 1 3. In the Admin Center, click **Apps and integrations** in the sidebar, then select **Zendesk API** and click **Get Started**. Img 2 4. Under the **Settings** tab, enable token access, then click **Add API token**. Img 3 5. You'll now see your Zendesk API token—copy and store it safely. 6. Combine your Zendesk email address and API token using the following format: ``` email_address/token:zendesk_token ``` Then, encode it in Base64. You can do this in a couple of ways: * Run the following command in your terminal (Linux/macOS): ``` echo -n 'email_address/token:zendesk_token' | base64 ``` * Use an [online Base64 encoder](https://www.base64encode.org/). 7. The encoded result will serve as your Zendesk API key. ### Integrate Zendesk into xpander.ai 1. Go to the **Connectors** section in the sidebar of your xpander.ai dashboard. 2. Select **Zendesk** from the available integrations. 3. Click **Enable**. 4. Enter a **connector name**, e.g., "xpander-zendesk". 5. Select **Integration User** as the authentication mode. 6. Select **API Key** as the authentication method. 7. Paste the Base64-encoded token into the provided field. 8. Choose **Basic** as the **Auth Type**. 9. Under **Interface specific settings**, enter your Zendesk domain name (e.g., `https://xpander-23038.zendesk.com`). 10. Save the configuration. Img 4 ## Integration of Zendesk into AI Agent Once you've configured your Zendesk account with the authentication option(s) described above, you can integrate it into your AI agent with xpander.ai: 1. In your xpander.ai dashboard, go to the **Agent Configuration** tab and select **Tools**, then click **Add Tools**. 2. Select **Connectors**. 3. Choose **Zendesk** with the same **connector name** you configured in the previous section (e.g., xpander-zendesk). 4. Select the available Zendesk operations that suit your use case. Img 5 ## Expose Zendesk as MCP Server Alternatively, you can also expose your Zendesk account as an MCP server. To do so: 1. Go to the **Connectors** section in the sidebar of your xpander.ai dashboard. 2. Select **Zendesk** with the same **connector name** you configured in the previous section (e.g., xpander-zendesk). 3. Click **MCP Configuration**. 4. Enter the MCP configuration into the appropriate settings of the client app you want to use (e.g., Cursor, Windsurf, Claude Desktop, etc.). Img 6 ## AI Agent Zendesk Prompt Library Below are possible prompts or use cases you can try after integrating Zendesk into your xpander AI agent: ``` Can you please create a ticket for {issue_description} under {org_name}? ``` ``` What's the status of ticket #{ticket_id}? ``` ``` Can you close all solved tickets for {org_name}? ``` ``` Can you update user {user_id} to have a new phone number {phone_number}? ``` ## Related Resources * [Understanding Model Context Protocol (MCP)](/guides/deploy/mcp) * \[Zendesk API Documentation]\([https://developer.zendesk.com/API](https://developer.zendesk.com/API) reference/) # Zoho Source: https://docs.xpander.ai/connectors/zoho Learn how to integrate AI agents with Zoho using xpander.ai. Create intelligent, low-code applications on Zoho Creator that leverage AI-driven automation, enabling your agents to analyze data, trigger workflows, and interact with customers seamlessly across your Zoho ecosystem. ## About Zoho Zoho offers a wide array of applications designed to streamline various business operations, including sales, marketing, customer support, finance, human resources, and more. This integration deals specifically with one of the features offered by Zoho, which is the Zoho Creator. Zoho Creator offers a wide array of applications designed to streamline various business operations, including sales, marketing, customer support, finance, human resources, and more. Zoho Creator is a low-code application development platform designed to empower users to build custom business applications with minimal coding knowledge. Zoho Creator key features: * **Rapid Application Development**: Accelerate app creation by up to 10 times using visual development tools and guided scripting. * **Cross-Platform Compatibility**: Applications built on Zoho Creator are natively compatible with web browsers, iOS, and Android devices, ensuring seamless access across platforms. * **Pre-Built Templates**: Access over 60 ready-to-use app templates to jumpstart development for various business needs. * **Workflow Automation**: Utilize drag-and-drop workflow builders and pre-written code snippets to automate business processes, schedule tasks, and manage approvals efficiently. ## Authentication Options Below are possible authentication options you can choose: ### Generate a Zoho API Key 1. Log in to your [Zoho API console](https://accounts.zoho.com/signin?servicename=AaaServer\&context=\&serviceurl=https%3A%2F%2Fapi-console.zoho.com%2F). 2. Choose the type of application you want to create. In this example, we’ll create a **Self Client** app. Img 1 3. Select **Self Client** and click **Create**. 4. You’ll see the **Client ID** and **Client Secret**. Next, you’ll need to generate an **authorization code**. 5. Go to the **Generate Code** tab. Under **Scope**, select the appropriate scopes for your app. You can find a full list in the [Zoho Creator documentation](https://www.zoho.com/creator/help/api/v2.1/oauth-overview.html). 6. Set the validity duration for the authorization code, then click **Create**. Img 2 7. Copy and save your **authorization code**. 8. To get your access token, run the following request: ```bash theme={"dark"} curl -X POST /oauth/v2/token \ -d "grant_type=authorization_code" \ -d "code=" \ -d "client_id=" \ -d "client_secret=" ``` Replace the placeholders with your actual values. You can find the `` for your Zoho account [here](http://accounts.zoho.com/oauth/serverinfo). 9. The response will include your **access token** and **refresh token**. ### Integrate Zoho into xpander.ai 1. In your xpander.ai dashboard, go to the **Connectors** section in the sidebar. 2. Select **Zoho** from the available integrations. 3. Click **Enable**. 4. Enter a **connector name**, e.g., "xpander-zoho". 5. Select **Integration User** for the authentication mode. 6. Choose **API Key** as the authentication method. 7. Paste your Zoho access token into the provided field. 8. Set the **Auth Type** to **Custom**. 9. In the **Custom header name** field, enter: `Authorization: Zoho-oauthtoken`. 10. Save the configuration. Img 3 ## Integration of Zoho into AI Agent Once you've configured your Zoho account with the authentication option(s) described above, you can integrate it into your AI agent with xpander.ai: 1. In your xpander.ai dashboard, go to the **Agent Configuration** tab and select **Tools**, then click **Add Tools**. 2. Select **Connectors**. 3. Choose **Zoho** with the same **connector name** you configured in the previous section (e.g., xpander-zoho). 4. Select the available Zoho operations that suit your use case. Img 4 ## Expose Zoho as MCP Server Alternatively, you can also expose your Zoho account as an MCP server. To do so: 1. Go to the **Connectors** section in the sidebar of your xpander.ai dashboard. 2. Select **Zoho** with the same **connector name** you configured in the previous section (e.g., xpander-zoho). 3. Click **MCP Configuration**. 4. Enter the MCP configuration into the appropriate settings of the client app you want to use (e.g., Cursor, Windsurf, Claude Desktop, etc.). Img 5 ## AI Agent Zoho Prompt Library Below are possible prompts or use cases you can try after integrating Zoho into your xpander AI agent: ``` Could you download the invoice PDF attached to record #{record_id} in the {report_name} report? ``` ``` Can you add these 50 new employee records to the {form_name} form in our HR application? ``` ``` Has the export job {job_id} for our sales data completed yet? ``` ``` Could you export all customer records from the {report_name} report in my {application_name}? ``` ## Related Resources * [Understanding Model Context Protocol (MCP)](/guides/deploy/mcp) * [Zoho Creator API Documentation](https://www.zoho.com/creator/help/api/v2.1/) # Zoom Source: https://docs.xpander.ai/connectors/zoom Learn how to integrate AI agents with Zoom using xpander.ai. Create intelligent virtual assistants that can join meetings, transcribe conversations, provide real-time insights, and automate follow-up actions seamlessly. ## About Zoom Zoom is a widely used video communications platform that offers services like: * **Video Conferencing**: Zoom's core feature allows users to hold virtual meetings with HD video and audio. It supports large groups, screen sharing, breakout rooms, and virtual backgrounds. * **Webinars**: Zoom lets users host large-scale webinars for marketing, training, or public speaking, with features like Q\&A, polling, and attendee management. * **Zoom Phone**: A cloud-based phone system that includes voice calling, voicemail, call routing, and integrations with Zoom Meetings. * **Zoom Rooms**: Hardware and software solutions for equipping conference rooms with video conferencing capabilities, allowing for seamless hybrid work setups. * **Chat and Collaboration Tools**: Zoom offers built-in team chat features for direct messaging and group collaboration. * **Integrations**: Zoom integrates with many third-party apps, such as Slack, Microsoft Teams, Google Workspace, and Salesforce. ## Authentication Options Below are possible authentication options you can choose: ### Generate a Zoom API Key 1. Go to the [Zoom App Marketplace](https://marketplace.zoom.us/). 2. Click the **Develop** button at the top right of your dashboard, then select **Build App**. Img 1 3. Choose **Server-to-Server OAuth App**, then click **Create**. 4. Give your app a name. 5. You’ll be shown the **Account ID**, **Client ID**, and **Client Secret**. Copy these values for later. Img 2 6. Fill out the required fields and add the necessary scopes to your app. 7. Finally, click **Activate your app**. Img 3 8. Open your terminal and run the following command: ```bash theme={"dark"} curl --request POST \ --url https://zoom.us/oauth/token \ --header 'Content-Type: application/x-www-form-urlencoded' \ --data-urlencode 'grant_type=account_credentials' \ --data-urlencode 'account_id=YOUR_ACCOUNT_ID' \ --data-urlencode 'client_id=YOUR_CLIENT_ID' \ --data-urlencode 'client_secret=YOUR_CLIENT_SECRET' ``` Replace the placeholders with your actual **Account ID**, **Client ID**, and **Client Secret**. 9. If successful, you’ll receive an **access token** in the response. ### Integrate Zoom into xpander.ai 1. In your xpander.ai dashboard, go to the **Connectors** section in the sidebar. 2. Select **Zoom** from the available integrations. 3. Click **Enable**. 4. Enter a **connector name**, e.g., "xpander-zoom". 5. Select **Integration User** for the authentication mode. 6. Choose **API Key** as the authentication method. 7. Paste the Zoom access token from the previous step into the provided field. 8. Set the **Auth Type** to **Bearer**. 9. Save the configuration. Img 4 ## Integration of Zoom into AI Agent Once you've configured your Zoom account with the authentication option(s) described above, you can integrate it into your AI agent with xpander.ai: 1. In your xpander.ai dashboard, go to the **Agent Configuration** tab and select **Tools**, then click **Add Tools**. 2. Select **Connectors**. 3. Choose **Zoom** with the same **connector name** you configured in the previous section (e.g., xpander-zoom). 4. Select the available Zoom operations that suit your use case. Img 5 ## Expose Zoom as MCP Server Alternatively, you can also expose your Zoom account as an MCP server. To do so: 1. Go to the **Connectors** section in the sidebar of your xpander.ai dashboard. 2. Select **Zoom** with the same **connector name** you configured in the previous section (e.g., xpander-zoom). 3. Click **MCP Configuration**. 4. Enter the MCP configuration into the appropriate settings of the client app you want to use (e.g., Cursor, Windsurf, Claude Desktop, etc.). Img 6 ## AI Agent Zoom Prompt Library Below are possible prompts or use cases you can try after integrating Zoom into your xpander AI agent: ``` Could you retrieve the meeting details for the call scheduled on {date} with {client_name}? ``` ``` Can you retrieve the participant list from our webinar on {topic} held last {day}? ``` ``` Could you create a new poll for our upcoming meeting about {topic_name}? ``` ``` Could you retrieve the cloud recording usage report from {start_date} to {end_date}? ``` ## Related Resources * [Understanding Model Context Protocol (MCP)](/guides/deploy/mcp) * [Zoom API Documentation](https://developers.zoom.us/docs/api/) # Agent Commands Source: https://docs.xpander.ai/developers/cli-reference/agent-commands Every command under `xpander agent` (control plane, local dev, graph, tools, NeMo). The `xpander agent` namespace covers agent management plus graph editing, agentic-tool discovery, and NeMo model-config sync. Most lifecycle commands also exist as top-level shortcuts (`xpander dev` ≡ `xpander agent dev`). ```bash theme={"dark"} xpander agent [agent] [options] ``` When `[agent]` is omitted, most commands show an interactive selection list of your agents. Use `--no-interactive` to fail instead of prompting. ## Discovery ### `xpander agent list` List all agents in your organization, sorted by creation date (newest first). ```bash theme={"dark"} xpander agent list xpander agent list --all --full --json ``` | Flag | Description | | --------------- | ----------------------------------------- | | `--json` | Output JSON instead of a table. | | `--all` | Include inactive agents. | | `--full` | Show the full API response (every field). | | `--profile ` | Profile to use. | ### `xpander agent list-json` Same as `agent list --json`, kept as a separate command for backwards compatibility. ```bash theme={"dark"} xpander agent list-json xpander agent list-json --all ``` | Flag | Description | | ------------------ | ------------------------ | | `--all` | Include inactive agents. | | `--profile ` | Profile to use. | ### `xpander agent get ` (alias `g`) Get details for a single agent. ```bash theme={"dark"} xpander agent get my-agent xpander agent g my-agent --json xpander agent get --agent-id abc123 ``` | Flag | Description | | --------------------- | ---------------- | | `--agent-id ` | Look up by ID. | | `--agent-name ` | Look up by name. | | `--json` | Output JSON. | | `--profile ` | Profile to use. | ### `xpander agent interactive` Drop into the interactive agent management TUI: list, pick, edit, delete, invoke without typing every command. ```bash theme={"dark"} xpander agent interactive ``` ## Control plane (CRUD) ### `xpander agent new` (alias `n`) Create a new agent in the xpander.ai cloud. ```bash theme={"dark"} xpander agent new xpander agent new --name "bot" --framework "agno" --folder "." xpander agent n --name "bot" --model "gpt-4o" --init --json ``` | Flag | Description | | ------------------------- | ------------------------------------------------------------------------- | | `--name ` | Agent name. | | `--model ` | LLM model id. Defaults to `gpt-4o`. | | `--framework ` | Template: `agno`, `agno-team`, or `base`. | | `--folder ` | Local folder to scaffold into. Setting this enables non-interactive mode. | | `--init` | After creation, run the initialization wizard. | | `--json` | Output the result as JSON. | | `--profile ` | Profile to use. | Without flags, the command runs an interactive wizard. Pass `--name`, `--framework`, and `--folder` together to run non-interactively in CI. ### `xpander agent update` Update an existing agent's metadata. ```bash theme={"dark"} xpander agent update --id abc123 \ --name "Bot v2" \ --role "Assistant" \ --goal "Answer questions about our product" \ --instructions "Be concise" \ --icon "🤖" ``` | Flag | Description | | ----------------------- | -------------------------- | | `--id ` | Agent to update. | | `--name ` | New name. | | `--role ` | New role. | | `--goal ` | New goal. | | `--instructions ` | New instructions. | | `--icon ` | New icon (emoji or URL). | | `--profile ` | Profile to use. | | `--json` | Output the result as JSON. | ### `xpander agent edit [agent]` (alias `o`) / `xpander agent open [agent]` Open the agent's configuration page in your browser. `edit` and `open` are equivalent. ```bash theme={"dark"} xpander agent edit my-agent xpander agent o my-agent xpander agent edit --agent-id abc123 ``` | Flag | Description | | --------------------- | --------------- | | `--agent-id ` | Open by ID. | | `--agent-name ` | Open by name. | | `--profile ` | Profile to use. | ### `xpander agent delete [agent]` (alias `del`) Permanently delete an agent. ```bash theme={"dark"} xpander agent delete my-agent xpander agent del my-agent --confirm ``` | Flag | Description | | --------------------- | ------------------------------------------------ | | `--agent-id ` | Delete by ID. | | `--agent-name ` | Delete by name. | | `--confirm` | Skip the destructive-action confirmation prompt. | | `--profile ` | Profile to use. | ## Local development ### `xpander agent init [agent-id]` (alias `i`) Download the agent's framework files into the current directory. ```bash theme={"dark"} xpander agent init my-agent xpander agent i my-agent --framework "agno" --folder "." xpander agent init my-agent --template ``` | Flag | Description | | ------------------------- | ------------------------------------------------------------ | | `--framework ` | Template to use: `agno`, `agno-team`, `base`. | | `--folder ` | Target directory. Setting this enables non-interactive mode. | | `--template` | Show the template-selection picker before initializing. | | `--profile ` | Profile to use. | Files written: * `Dockerfile` * `requirements.txt` * `xpander_handler.py` * `.env` Plus framework-specific config (`xpander_config.json`, `agent_instructions.json`, …). The base templates can be inspected via [`xpander agent templates`](#xpander-agent-templates) (below). ### `xpander agent templates` Manage and discover agent templates. | Subcommand | Purpose | | ------------------------------------ | ------------------------------------------------------------------ | | `xpander agent templates list` | List all available templates. Pass `--all` to include hidden ones. | | `xpander agent templates categories` | List template categories. | ### `xpander agent dev [agent]` Run the agent locally for testing. ```bash theme={"dark"} xpander agent dev my-agent ``` | Flag | Description | | --------------- | ----------------------------------------------------------- | | `--profile ` | Profile to use. | | `--path ` | Path to the agent directory. Defaults to current directory. | Starts the agent in your local Python environment using the `.env` file in the working directory. Use this to iterate on `xpander_handler.py` against real prompts. ## Invocation (testing) ### `xpander agent invoke [agent] [message...]` Test an agent (running locally or live on the platform) and print the response. ```bash theme={"dark"} xpander agent invoke # interactive: pick agent, then enter message xpander agent invoke my-agent # pick this agent, prompt for message xpander agent invoke my-agent "Hello" # direct invocation (uses API by default) xpander agent invoke --agent-id abc123 "status" xpander agent invoke --json my-agent "summarize" # JSON response xpander agent invoke --local my-agent "test" # use local xpander_handler.py xpander agent invoke --webhook my-agent "ping" # use webhook invocation ``` | Flag | Description | | --------------------- | -------------------------------------------- | | `--agent ` | Agent name or ID. | | `--agent-id ` | Invoke by exact ID. | | `--agent-name ` | Invoke by name. | | `--message ` | Message to send (alternative to positional). | | `--profile ` | Profile to use. | | `--json` | Output raw JSON response. | | `--local` | Use the local `xpander_handler.py`. | | `--api` | Use API invocation. (Default.) | | `--webhook` | Use webhook invocation. | When run inside an agent directory with a `.env` file, `xpander agent invoke "hi"` infers the agent from `.env` and treats `"hi"` as the message. The CLI caches the agent list for 24 hours, so name lookups stay fast across invocations. ## Graph An agent's **operation graph** is the directed graph of connector operations the agent is allowed to call, along with the allowed transitions between them. The platform uses it both to constrain tool selection during a run and to render the visual workflow shown in the dashboard. Most users edit graphs through the dashboard; the CLI commands here are useful for scripting and CI. ### `xpander agent graph create` Create an operation graph for an agent. ```bash theme={"dark"} xpander agent graph create -a abc123 ``` | Flag | Description | | --------------------- | ------------------------------ | | `-a, --agent-id ` | Agent to create the graph for. | ### `xpander agent graph View` View the graph structure of an agent. ```bash theme={"dark"} xpander agent graph View -a abc123 ``` | Flag | Description | | --------------------- | -------------------------- | | `-a, --agent-id ` | Agent whose graph to view. | The `View` subcommand is capitalized in the CLI: type it exactly as `xpander agent graph View`. ## Tools The xpander platform organizes tools as **interfaces** (a connector or service: Slack, GitHub, Salesforce, etc.) and **operations** (the individual API calls each interface exposes: `slack.send_message`, `github.create_issue`, and so on). Use these commands to discover interface IDs and the operations they offer when you're building agent configs by hand or scripting against the API. ### `xpander agent tools interfaces` List available agentic interfaces (categories of connectors and tools your agents can use). ```bash theme={"dark"} xpander agent tools interfaces ``` | Flag | Description | | ------------------ | --------------- | | `--profile ` | Profile to use. | ### `xpander agent tools operations` List the operations exposed by a specific interface. ```bash theme={"dark"} xpander agent tools operations --interface ``` | Flag | Description | | ------------------ | --------------------------------------------- | | `--interface ` | Interface ID (from `agent tools interfaces`). | | `--profile ` | Profile to use. | ## NeMo NeMo support lives at the top level (not under `agent`), but it's agent-config-related: ### `xpander nemo pull` Pull an agent's model configuration into a local NeMo config file. ```bash theme={"dark"} xpander nemo pull ``` | Flag | Description | | ------------------ | --------------- | | `--profile ` | Profile to use. | ### `xpander nemo push` Push your local NeMo config changes back to the agent. ```bash theme={"dark"} xpander nemo push --confirm ``` | Flag | Description | | ------------------ | -------------------------- | | `--profile ` | Profile to use. | | `--confirm` | Skip confirmation prompts. | ## Common patterns ### Non-interactive for CI ```bash theme={"dark"} xpander agent new --name "bot" --framework "agno" --folder "." ``` Combine with `--no-interactive` (global) to fail fast if any prompt would otherwise appear. # Auth & Config Source: https://docs.xpander.ai/developers/cli-reference/auth-config Authenticate, manage profiles, and sync deployment secrets. The xpander CLI authenticates per profile and stores credentials at `~/.xpander/credentials`. You can have multiple profiles for different organizations or environments (production, staging, …). ## `xpander login` (alias `l`) Authenticate via browser. Opens xpander.ai in your default browser, completes the OAuth flow, and writes credentials to the active profile. ```bash theme={"dark"} xpander login xpander login --profile staging xpander login --new # force a new profile even if one exists ``` | Flag | Description | | ------------------ | ------------------------------------------------------------------------------------ | | `--profile ` | Profile name to write credentials to. Defaults to the active profile (or `default`). | | `--new` | Create a new profile even if one already exists with this name. | ## `xpander configure` (alias `c`) Set up API credentials manually (for environments without a browser, or when you already have an API key). ```bash theme={"dark"} xpander configure xpander configure --key sk-... --org 8d185373-... --profile staging xpander c --key sk-... --no-validate ``` | Flag | Description | | ------------------------- | --------------------------------------------------------------------------------------------------------------- | | `--key ` | API key to store. If omitted, the wizard prompts. | | `--org ` | Organization ID. Optional: auto-detected from the key if omitted. | | `--profile ` | Profile to write to. | | `--no-validate` | Skip credential validation against the cloud (useful when the API is unreachable but you know the key is good). | The wizard: 1. Stores your API key in the profile. 2. Validates against xpander.ai (unless `--no-validate`). 3. Auto-detects your organization ID. 4. Writes both to `~/.xpander/credentials`. Output: ```text theme={"dark"} ? Enter your Xpander API key: ✔ API key validation successful API key saved to profile "default". Detecting organization ID... ✔ Organization ID detected: 8d185373-8b24-47a7-8607-3e9036b968bb Credentials stored at: ~/.xpander/credentials ``` ## `xpander profile` Manage profiles. ```bash theme={"dark"} xpander profile --list # list all profiles xpander profile --set-default staging # set the default profile xpander profile --new # wizard for a new profile xpander profile --new staging # create profile named "staging" xpander profile --edit staging # edit an existing profile xpander profile --verify # verify the current profile works xpander profile --verify staging # verify a specific profile ``` | Flag | Description | | ---------------------- | --------------------------------------------------------------------------------- | | `--list` | List all profiles. | | `--set-default ` | Set a profile as the default. | | `--new [name]` | Create a new profile. Without a name, runs an interactive wizard. | | `--edit ` | Edit an existing profile. | | `--verify [name]` | Verify a profile by hitting the API. Without a name, verifies the active profile. | Use `--profile ` on any command to override the active profile for a single call: ```bash theme={"dark"} xpander agent list --profile staging xpander agent dev my-agent --profile production ``` ## Auth priority When multiple credential sources are present, the CLI resolves auth in this order: 1. `--api-key` on the command line. 2. `XPANDER_API_KEY` environment variable. 3. `~/.xpander/credentials` (the active profile). This lets CI runners override the local profile without touching it. ## Files and locations | Path | Purpose | | ------------------------ | --------------------------------------------------- | | `~/.xpander/credentials` | Per-profile credentials (API key, organization ID). | | `.env` (project root) | Local env vars. Read by `xpander agent dev`. | # Overview Source: https://docs.xpander.ai/developers/cli-reference/overview Install the xpander CLI, authenticate, and run your first command. The xpander CLI is your command-line for managing agents and scaffolding and running local projects. It covers three areas: | Area | What it does | | --------------------- | -------------------------------------------------------------- | | **Control plane** | Create, edit, delete, invoke agents in the cloud. | | **Local development** | Scaffold framework templates and run agents locally. | | **NeMo sync** | Pull/push agent model configuration to/from local NeMo config. | ## Install **Requirements:** Node.js 20+, Python 3.12+. ```bash theme={"dark"} npm install -g xpander-cli ``` Verify the install: ```bash theme={"dark"} xpander --version ``` Authenticate (opens a browser): ```bash theme={"dark"} xpander login ``` Or set credentials manually: ```bash theme={"dark"} xpander configure ``` Credentials are stored at `~/.xpander/credentials` and scoped per profile (default profile is `default`). ## First command ```bash theme={"dark"} xpander agent new ``` The wizard prompts for a name, creates the agent in your org, and offers to load the framework template into the current directory. ## Global options These apply to every command (and to `xpander` itself): | Flag | Description | | ------------------- | ------------------------------------------------------------------------------------------------ | | `-v, --version` | Print the CLI version and exit. | | `--output ` | Output format: `json` or `table`. Defaults to `table`. | | `--profile ` | Profile to use. Falls back to the active profile. | | `--api-key ` | Override the active profile's API key for this command. | | `-y, --yes` | Auto-answer "yes" to every prompt (non-interactive mode). | | `--no-interactive` | Disable interactive prompts. Commands fail if a required input is missing rather than prompting. | | `-h, --help` | Print help for the current command. | ## Top-level commands | Command | Alias | Purpose | | ------------------------------ | ----- | ----------------------------------------------------------------- | | `xpander configure` | `c` | Set up API credentials. | | `xpander login` | `l` | Authenticate via browser. | | `xpander profile` | – | Manage profiles. | | `xpander agent` | `a` | Manage agents (full namespace: see Agent Commands). | | `xpander initialize [agent]` | `i` | Shortcut for `agent init`. | | `xpander dev [agent]` | – | Shortcut for `agent dev`. | | `xpander invoke [agent] [msg]` | – | Shortcut for `agent invoke`. | | `xpander nemo` | – | Sync agent model config with local NeMo config (`pull` / `push`). | | `xpander help [command]` | – | Print help for a command. | Most lifecycle commands exist both as top-level shortcuts (`xpander dev`) and inside the `agent` namespace (`xpander agent dev`). Both forms are documented in [Agent Commands](/developers/cli-reference/agent-commands). ## Where to next Every command under `xpander agent`: control plane, local dev, graph, tools, NeMo. `login`, `configure`, `profile`. `x a n`, `x a d`, and friends. # Shortcuts Source: https://docs.xpander.ai/developers/cli-reference/shortcuts Aliases and shorthand for common CLI commands. The CLI ships with single-letter aliases for the verbs you use most. Aliases compose: `xpander` → `x`, `agent` → `a`, then a single letter for the action. ```bash theme={"dark"} # Full xpander agent new # Short x a n ``` ## Authentication | Shortcut | Full command | | -------- | ------------------- | | `x l` | `xpander login` | | `x c` | `xpander configure` | ## Top-level lifecycle (apply to active agent or to `[agent]`) These exist as both top-level shortcuts and `agent` subcommands. The forms are equivalent: the top-level form is shorter. | Shortcut | Full | Equivalent | | ------------------------------ | -------------------- | -------------------------------- | | `x i [agent]` | `xpander initialize` | `xpander agent init` (`agent i`) | | `xpander dev [agent]` | – | `xpander agent dev` | | `xpander invoke [agent] "msg"` | – | `xpander agent invoke` | ## Agent namespace | Shortcut | Full command | | -------------------------- | -------------------------------------- | | `x a` | `xpander agent` | | `x a n` | `xpander agent new` | | `x a g ` | `xpander agent get` | | `x a i [agent]` | `xpander agent init` | | `x a o [agent]` | `xpander agent edit` (or `agent open`) | | `x a del [agent]` | `xpander agent delete` | | `x a invoke [agent] "msg"` | `xpander agent invoke` | ## Common chains ```bash theme={"dark"} x a n # create new agent (interactive) x a i # scaffold its files locally xpander dev # run it locally ``` When `[agent]` is omitted, the CLI shows an interactive selection list: handy when you only have one or two agents in a profile, or use `--no-interactive` to fail instead of prompting. ## Global flags (work with every shortcut) | Flag | Description | | ------------------ | ------------------------------------------------------ | | `-v, --version` | Print version. | | `--profile ` | Use a specific profile. | | `--api-key ` | Override API key for this command. | | `--output ` | `json` or `table`. | | `-y, --yes` | Auto-approve prompts. | | `--no-interactive` | Disable interactive prompts (fail if input is needed). | | `-h, --help` | Show help for the current command. | These compose with shortcuts: ```bash theme={"dark"} x a list --json --profile staging x a d --confirm --no-interactive ``` # Core Concepts Source: https://docs.xpander.ai/developers/core-concepts How agents, tasks, threads, tools, and memory map onto SDK classes xpander.ai is a platform for building production AI agents. An *agent* is the platform's central object: a configured LLM with instructions, tools, knowledge bases, memory, and a deployment target. This page is the SDK companion that tells you which Python class each of those concepts becomes when you `import xpander_sdk`. The job of this page: when you see `Backend`, `Task`, or `agent.tools.functions` in code, you should know exactly what they are without context-switching back to the conceptual docs. The same model from the Agent Studio side. Read that for the concepts; read this for the class names. ## The two halves xpander splits responsibilities between a **control plane** (cloud or self-hosted) and **your runtime**. Reading code, you'll move between three boundaries constantly: ``` Control plane SDK objects in your process Framework (cloud / self-hosted) ┌────────────────────┐ Agent definition ───▶ │ Backend, Agent │ ─▶ Splatted into AgnoAgent(**args) Tools / connectors ──▶ │ ToolsRepository │ ─▶ agent.tools.functions Knowledge bases ────▶ │ KnowledgeBase │ ─▶ retriever wired into args Postgres (sessions) ─▶ │ Agent.aget_db() │ ─▶ args["db"] │ │ Task created ────────▶ │ @on_task → Task │ ─▶ Your handler runs └────────────────────┘ ``` The SDK objects are thin wrappers around the platform's HTTP API. They're how you read and write to it from Python. ## Backend `Backend` is the gateway. It's the only class that knows how to talk to the control plane to fetch a fully resolved agent definition. Inside an `@on_task` handler, the typical use is one line: ```python theme={"dark"} from xpander_sdk import Backend backend = Backend(configuration=task.configuration) args = await backend.aget_args(task=task) ``` The returned dict contains everything Agno needs: 1. Model client with credentials. 2. Instructions (system prompt, role, goal). 3. Tools (connectors + your `@register_tool` functions). 4. Session DB. 5. Memory settings. 6. Output schema. Splatting it into `agno.agent.Agent(**args)` is the production pattern. Pass the current `task` so the SDK can forward task-level overrides (instructions overrides, expected output, output schema) through to the framework. Both `get_args` (sync) and `aget_args` (async) accept the same arguments. The async form is what you'll use inside `@on_task` and any FastAPI service; the sync form is fine in scripts and notebooks. This async/sync pairing holds across the entire SDK. ## Agent `Agent` is the loaded, in-memory representation of an agent. It carries everything the control plane knows about it: 1. Name and unique identifier. 2. Instructions (role, goal, general). 3. Framework selection. 4. Model + provider. 5. Deployment type (`Serverless`). 6. Tools, knowledge bases, sub-agents. 7. Memory settings. ```python theme={"dark"} from xpander_sdk import Agents agent = Agents().get(agent_id="...") print(agent.name, agent.model_provider, agent.model_name) print(agent.deployment_type) # AgentDeploymentType.Serverless print(len(agent.tools.list)) # Tools available, including connectors ``` Two collection helpers: * **`Agents().get(agent_id=...)`**: returns a fully loaded `Agent`. Heavyweight. * **`Agents().list()`**: returns `AgentsListItem` summaries (just names + IDs). Faster when you're enumerating. Call `.aload()` on a list item to upgrade it to a full `Agent`. ## Task A `Task` is one execution. It has an ID, a status, an input, and a result. ```python theme={"dark"} task = agent.create_task(prompt="Summarize the attached PDF", file_urls=["https://example.com/report.pdf"]) print(task.id, task.status) # "executing", typically ``` Status values: `pending`, `executing`, `completed`, `failed`, plus a few transitional states. Inside `@on_task`, the platform creates the Task for you and you receive it as a parameter. Your job is to set `task.result` and return the task. The decorator marks it `completed` if you return cleanly, or `failed` if you raise. Helpers on `Task` for framework integration: * **`task.to_message()`**: joins input text, file URLs, and any embedded readable file content into a single string ready to feed into Agno. * **`task.get_files()`**: returns PDFs as `agno.media.File` objects. * **`task.get_images()`**: returns image URLs as `agno.media.Image` objects. Load a task by ID later with `Tasks().get(task_id)`. That's how you implement retries, audit logging, or deferred result fetching. ## Threads (sessions) The SDK doesn't have a class called `Thread`. What Agent Studio shows as a thread is a `session_id` shared across multiple Tasks, with the conversation history persisted in the agent's Postgres schema. If your agent has [Agno session storage enabled](/developers/memory/session-storage), you can list and inspect those sessions directly: ```python theme={"dark"} sessions = agent.get_user_sessions(user_id="user_123") for s in sessions: print(s.session_id, len(s.messages)) # Load a single session session = agent.get_session(session_id="sess_abc") # Wipe it agent.delete_session(session_id="sess_abc") ``` Behind the scenes, `agent.get_db()` returns the underlying `agno.db.postgres.AsyncPostgresDb` instance scoped to this agent's schema. Reach for it directly only when you want to do something Agno doesn't expose, like writing custom Postgres queries against session metadata. ## Connectors and tools Whatever you select in Agent Studio under "Tools" becomes available in code as part of `agent.tools`. There are three flavors: * **Connectors**: pre-built integrations from the catalog (Slack, Gmail, GitHub, 2,000+). Authenticated and configured in Agent Studio. * **Custom tools**: Python functions you've decorated with `@register_tool` in your handler. * **MCP servers**: model-context-protocol servers, either remote (URL) or local (process), wired in through Agent Studio. * **`agent.tools`**: the unified `ToolsRepository` that flattens all three into one list. `agent.tools.list` enumerates `Tool` objects; `agent.tools.functions` returns normalized callables ready to bind to LangChain, OpenAI Agents SDK, or any framework that accepts plain Python functions. ```python theme={"dark"} @register_tool def lookup_customer(customer_id: str) -> dict: """Fetch a customer record from the internal API.""" ... # After the agent loads, lookup_customer shows up alongside connectors: [t.name for t in agent.tools.list] # -> ['SlackPostMessage', 'GmailSend', 'lookup_customer', ...] ``` Each `Tool` has a `parameters` JSON schema that the agent's LLM uses to call it. The SDK auto-generates that schema from your function's type hints and docstring, which is why annotation matters more than usual here. `agent.tools.functions` is framework-agnostic. You can import an xpander agent's tool list into any LLM client that accepts plain Python callables, including raw `openai.OpenAI().chat.completions.create(tools=[...])` calls or a homegrown ReAct loop. This is the escape hatch when none of the supported framework adapters fit your stack. ## Knowledge bases `KnowledgeBase` represents one document collection. The platform-managed type is the default; external KBs (your own vector store) are an advanced setup. ```python theme={"dark"} from xpander_sdk import KnowledgeBases kbs = KnowledgeBases() kb = kbs.get(knowledge_base_id="...") kb.add_documents([ "https://example.com/handbook.pdf", "https://example.com/runbook.md", ]) results = kb.search(search_query="how do we handle refunds?", top_k=5) ``` Inside an agent, a KB is attached through `agent.knowledge_bases` and queried automatically by the framework. Call `kb.search` directly only when you're building something outside the agent loop, like a search box or a one-off enrichment job. ## Memory There are three memory layers, and they're not the same thing. The Agno framework configures all of them through `agent.agno_settings`: * **Session storage** (`session_storage=True`, default): keeps conversation history within a single thread. Postgres-backed, scoped per agent. * **User memories** (`user_memories=True` or `agentic_memory=True`): facts the agent should remember about a specific user, across all their sessions. The two flags select between manual and agentic-managed mode. * **Agent memories** (`agent_memories=True` or `agentic_culture=True`): organization-wide knowledge the agent should carry into every conversation. Same two-flag pattern. Each layer is a separate switch because they each have a cost and a use case: 1. Session storage is essentially free. 2. User and agent memories cost LLM calls to maintain. Pick what you need, leave the rest off. The deep dive is in [Memory & State](/developers/memory/session-storage). ## Decorators The SDK exports a small set of decorators that handle the lifecycle for you: ```python theme={"dark"} from xpander_sdk import on_task, on_boot, on_shutdown, register_tool from xpander_sdk import on_tool_before, on_tool_after, on_tool_error from xpander_sdk import on_auth_event ``` What each one does: * **`@on_task`**: the entry point. Stands up the HTTP server and subscribes to the platform task stream. * **`@on_boot` / `@on_shutdown`**: lifecycle hooks that run before and after the handler is registered. * **`@register_tool`**: turns a Python function into an agent tool. SDK generates the JSON schema from your type hints. * **`@on_tool_before` / `@on_tool_after` / `@on_tool_error`**: observe tool calls without modifying the tools themselves. Use for logging, metrics, alerting. * **`@on_auth_event`**: fires when an MCP OAuth flow needs the user to log in. You'll typically need `@on_task` plus `@register_tool`. The rest are situational and covered in their own pages. ## Configuration `Configuration` is the explicit form of the credentials and base URL. Most code never instantiates it: the SDK reads from `XPANDER_API_KEY`, `XPANDER_ORGANIZATION_ID`, and `XPANDER_BASE_URL` automatically. ```python theme={"dark"} from xpander_sdk import Configuration config = Configuration( api_key="...", organization_id="...", base_url="https://agent-controller.acme.com", # for self-hosted ) backend = Backend(configuration=config) ``` Self-hosted deployments are the main reason to construct one explicitly. You need a custom `base_url`, and the agent controller's API key, not your cloud key. See [SDK configuration](/developers/sdk-reference/overview#configuration) for the full setup. ## Cheat sheet A one-line answer for the questions you'll have most often: | Question | Answer | | ------------------------------------------ | ------------------------------------------------------------------------------------------------------- | | Where do I configure the agent's behavior? | Agent Studio. The SDK reads it. | | Where do my custom tools live? | In your `xpander_handler.py`, decorated with `@register_tool`. | | How do I run an agent in code? | Inside `@on_task`: `Agent(**(await Backend(...).aget_args(task=task)))`. Framework-specific for others. | | How do I receive incoming tasks? | A function decorated with `@on_task`. | | How do I find session data? | `agent.get_user_sessions(user_id)` or `agent.get_session(session_id)`. | | How do I add a document to a KB? | `KnowledgeBases().get(kb_id).add_documents([url])`. | | Async or sync? | Every method has both. Async in production, sync in scripts. | ## Next steps What `Backend.aget_args()` actually wires up, with the AgnoSettings reference. The full `@register_tool` decorator surface. Session storage, user memories, and agent memories explained. Per-method reference for every class on this page. # Invocation Channels Source: https://docs.xpander.ai/developers/deployment/invocation-channels How users and other systems reach a deployed agent A deployed agent doesn't care how a task arrives. The same `@on_task` handler runs whether the input came from a Slack message, a webhook, a cron trigger, or another agent. You enable channels per agent in the Workbench under the agent's **Channels** tab. ## REST API The default channel. Every agent is reachable through the platform's REST API as soon as it's deployed: ```bash theme={"dark"} curl -X POST "https://api.xpander.ai/v1/agents/{agent_id}/invoke" \ -H "x-api-key: $XPANDER_API_KEY" \ -H "Content-Type: application/json" \ -d '{"input": {"text": "Summarize the attached file"}}' ``` Three invocation modes: | Mode | Endpoint | Best for | | ---------- | ---------------- | ---------------------------------------------------------------------------------------------------------------------------- | | **Sync** | `/invoke` | Short tasks (under 30s) where the caller needs the answer immediately. Blocks until complete, returns the full result. | | **Async** | `/invoke/async` | Long-running tasks or callers that can't hold a connection open. Returns a task ID immediately; poll or stream events later. | | **Stream** | `/invoke/stream` | Real-time UIs. Returns a Server-Sent Events stream of `TaskUpdateEvent`s as the agent runs. | Full endpoint reference: [REST API → Agents](/api-reference/v1/agents/invoke-sync). ## Slack Deploys your agent as a bot in your Slack workspace. Any DM or channel mention routes to your agent's `@on_task` handler. The user who sends the message becomes the `user_id` on the task, so [user memories](/developers/memory/user-memories) work out of the box. Set up in the Workbench under the agent's **Channels** tab. Each Slack workspace is one connection; the Workbench walks through OAuth. ## Webhooks Webhooks let any system that can make an HTTP POST trigger an agent run: automation platforms like Zapier, form submissions, CI/CD pipelines, or your own backend. ### Enable In Agent Studio, open the **Channels** tab, enable **Webhook**, and click **Configure and test**. The tester shows your payload URL (with agent ID and API key embedded) and a ready-to-use cURL command. ### Make requests All webhook requests are POST to `https://webhook.xpander.ai/`: ```bash theme={"dark"} curl -X POST 'https://webhook.xpander.ai/?agent_id=YOUR_AGENT_ID' \ -H 'Content-Type: application/json' \ -H 'x-api-key: YOUR_API_KEY' \ -d '{"prompt": "Summarize the latest support tickets"}' ``` **Required parameters:** | Parameter | Location | | ----------- | ---------------------- | | `agent_id` | Query string or body | | `x-api-key` | Header or query string | **Optional parameters:** | Parameter | Type | Description | | ------------------------------------ | ------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | `prompt` | string | Text input for the agent. | | `asynchronous` | boolean | Return immediately without waiting. Default: `false`. | | `task_id` | string | Continue an existing conversation thread. | | `user_id` | string | User identifier for tracking and memory scoping. | | `user_email` | string | User email for personalization. | | `user_first_name` / `user_last_name` | string | User name for personalization. | | `getter` | string | Dot-notation path to extract from the response instead of returning the full payload. | | `json` | boolean | Parse the result as JSON instead of returning a string. | | `user_tokens` | string (JSON) | Pre-authenticated MCP OAuth tokens (see below). | | `disable_attachment_injection` | boolean | When `true`, uploaded files are not injected into the LLM context window. File URLs are still available to the agent's tools, but raw content is not prepended to the prompt. Useful when files are large or a tool handles processing directly. | Any additional fields in the request body are passed to the agent as context. When the same parameter appears in multiple places, query parameters take priority over body parameters, which take priority over defaults. ### Sync vs async **Synchronous** (default): blocks until the agent finishes and returns the full result. ```json theme={"dark"} { "id": "task-uuid", "agent_id": "your-agent-id", "status": "completed", "result": "The agent's response...", "created_at": "2026-01-29T00:40:46.161472+00:00", "finished_at": "2026-01-29T00:40:47.919145+00:00", "source": "webhook", "execution_attempts": 1 } ``` **Asynchronous**: set `asynchronous=true` to return immediately. Best for long-running tasks, file processing, or when you don't need the result inline. ```bash theme={"dark"} curl -X POST 'https://webhook.xpander.ai/?agent_id=YOUR_AGENT_ID&asynchronous=true' \ -H 'x-api-key: YOUR_API_KEY' \ -d '{"prompt": "Generate the monthly report"}' ``` Returns `{"status": "Started"}` immediately. Check the Monitor tab for the result. ### Upload files Upload files using `multipart/form-data`. The agent automatically processes them: OCR for images, text extraction for PDFs, transcription for audio. ```bash theme={"dark"} curl -X POST 'https://webhook.xpander.ai/?agent_id=YOUR_AGENT_ID' \ -H 'x-api-key: YOUR_API_KEY' \ --form 'files=@"/path/to/document.pdf"' \ --form 'files=@"/path/to/image.png"' ``` Supported formats: PDF, DOC, DOCX, TXT, XLS, XLSX, CSV, PNG, JPEG, GIF, WEBP, SVG, ZIP. Uploaded files are stored on the xpander platform and exposed to your agent through presigned URLs scoped to your organization. URLs remain valid for 30 days after upload. For large batches (10+ files), use async mode and break uploads into batches of 5–10 files. ### Extract data from responses Use `getter` with dot notation to extract a specific field from the agent's response instead of the full object: ```bash theme={"dark"} curl -X POST 'https://webhook.xpander.ai/?agent_id=YOUR_AGENT_ID&getter=result.summary' \ -H 'x-api-key: YOUR_API_KEY' \ -d '{"prompt": "Analyze quarterly report"}' ``` Returns the extracted value directly: `"Q4 revenue increased 15%"`. ### Map dynamic parameters Use `params_mapping` as a query parameter to extract values from nested payload fields and map them to webhook parameters. Useful for Telegram bots, WhatsApp, and other messaging platforms where identifiers are nested: ```bash theme={"dark"} curl -X POST 'https://webhook.xpander.ai/?agent_id=YOUR_AGENT_ID¶ms_mapping={"task_id":"message.chat.id","prompt":"message.text","user_email":"message.from.email"}' \ -H 'x-api-key: YOUR_API_KEY' \ -d '{ "message": { "chat": {"id": 123456789}, "from": {"email": "user@example.com"}, "text": "Hello agent!" } }' ``` Supports all standard parameters: `task_id`, `user_id`, `user_email`, `user_first_name`, `user_last_name`, `prompt`. ### Pass MCP OAuth tokens If your agent uses MCP servers with OAuth authentication, pass pre-authenticated user tokens via `user_tokens` to bypass the interactive OAuth flow during webhook execution: ```bash theme={"dark"} curl -X POST 'https://webhook.xpander.ai/?agent_id=YOUR_AGENT_ID' \ -H 'x-api-key: YOUR_API_KEY' \ -d '{ "prompt": "Check my calendar", "user_email": "user@example.com", "user_tokens": { "mcp-graph-item-uuid-1": "user-access-token-abc123" } }' ``` To find the graph item IDs for your MCP servers, call the [Get Agent API](/api-reference/v1/agents/get-agent) and inspect `graph.items` for entries with `type: "mcp"`. ### Error codes | Status | Response | Cause | | ------ | ------------------------------------- | ------------------------------------------ | | 400 | `{"detail": "agent_id is required"}` | Missing `agent_id` parameter. | | 401 | `{"detail": "API key not specified"}` | Missing `x-api-key` header or query param. | | 403 | `{"detail": "Invalid API key"}` | Wrong API key or no access to this agent. | The `x-api-key` header is the only auth on the webhook endpoint by default. If you need request signing (HMAC for GitHub webhooks, signature verification for Stripe), validate it inside your handler before consuming the payload. The platform doesn't validate third-party signatures for you. ## MCP (Model Context Protocol) Exposes your agent as an MCP server so developer tools like Claude Desktop, Cursor, and VS Code can call it directly. Your team works in the tools they already have; xpander handles running the agent. MCP is not available for Personal Agents. Create a [Custom Agent](/guides/agents/agent-configuration) to use MCP. ### Enable In Agent Studio, open the **Channels** tab, enable **MCP**, and click **Details**. The modal shows your MCP server URL, API key, and transport options. Under **Easy setup**, select your client and copy the ready-to-paste configuration. Click **Publish** to make the server live. ### Connect from a client The MCP server supports two transports: | Transport | URL | | ------------------ | --------------------------------------------- | | **HTTP** (default) | `https://mcp.xpander.ai/ag_YOUR_AGENT_ID/` | | **SSE** | `https://mcp.xpander.ai/ag_YOUR_AGENT_ID/sse` | HTTP works with all current MCP clients. SSE (Server-Sent Events) enables server-initiated updates during long-running tasks. **Easy setup for Cursor, Claude Desktop, Windsurf**: Agent Studio generates an `npx install-mcp` command per client. ```bash theme={"dark"} npx install-mcp \ --name "" \ --client cursor \ --header "x-api-key:" \ -y --oauth no ``` | Placeholder | What to use | | ----------- | ------------------------------------------------------------------------------- | | `` | The per-agent MCP URL from the Details modal (append `/sse` for SSE transport). | | `` | A short slug for the server in your client's MCP list, e.g. `support-bot`. | | `` | The API key from the Details modal. | Swap `--client cursor` for `--client claude` or `--client windsurf`. Run once per client. **Raw JSON** for any other MCP-compatible client: ```json theme={"dark"} { "your_agent_name": { "command": "npx", "args": [ "mcp-remote", "https://mcp.xpander.ai/ag_YOUR_AGENT_ID/", "--header", "Authorization:${AUTH_TOKEN}" ], "env": { "AUTH_TOKEN": "Bearer YOUR_API_KEY" } } } ``` Paste into the client's config file (e.g., `~/Library/Application Support/Claude/claude_desktop_config.json` on macOS). Restart the client after saving. ### Available tools Each agent's MCP server exposes two tools. The flow is asynchronous because agent runs can take seconds to minutes. Call `invoke_agent` to start a task, then poll `get_task_status` until it completes. | Tool | What it does | | ----------------- | --------------------------------------------------------------------------------------------------- | | `invoke_agent` | Creates an asynchronous agent task and returns the task details immediately, including the task ID. | | `get_task_status` | Checks the state of a task created with `invoke_agent` and returns its result once complete. | **`invoke_agent` parameters:** | Parameter | Required | Description | | --------- | -------- | --------------------------------------------- | | `prompt` | Yes | Natural language prompt to send to the agent. | **`get_task_status` parameters:** | Parameter | Required | Description | | --------- | -------- | ----------------------------------------- | | `task_id` | Yes | The task ID returned from `invoke_agent`. | ### Authentication and security Each MCP server is protected by a per-agent API key generated in Agent Studio. The client passes it on every request as an `x-api-key` header (via `npx install-mcp`) or as `Authorization: Bearer ` (Raw JSON). No interactive OAuth. * **Per-agent scope**: the key only authorizes calls to that agent's two MCP tools. It can't access other agents or org-level operations. * **Revoke anytime**: rotate or revoke the key from the MCP section of the Channels tab. The API key is stored in the client's MCP config file. Treat that file as a secret. Don't commit it or share it. ### Troubleshooting Verify your `claude_desktop_config.json` is valid JSON. Check the file location: `~/Library/Application Support/Claude/claude_desktop_config.json` on macOS. Restart Claude Desktop completely. Check Claude logs at `~/Library/Logs/Claude/mcp.log`. Confirm the API key in your MCP config matches the one in the Agent Studio Details modal. If you rotated the key, re-run `install-mcp` or update the Raw JSON config. Check that the agent isn't restricted to specific users in org permissions. Verify the agent is published in Agent Studio and not stopped or in an error state. Check the agent's logs in the Monitor tab. ## Scheduled tasks (cron) A cron expression that creates a task on a schedule. The task input is whatever you configure in the Workbench: a fixed prompt or a templated one with placeholders. The agent's `@on_task` handler runs as if a user invoked it. Use this for recurring work like "every morning, summarize yesterday's deploys" or "every hour, check for new GitHub issues and triage them." ## Agent-to-agent (A2A) A2A lets other agents (inside or outside your organization) discover and invoke this agent via Google's Agent2Agent protocol. This is how multi-agent teams compose: a manager agent delegates to specialist agents by calling them as tools. ### Enable In Agent Studio, open the **Channels** tab, enable **A2A**, then: 1. Click **Agent card** to see the agent's A2A identity: its Agent A2A URL, name, and version. This is what external agents use to discover and call it. 2. Click **Manage API keys** to generate credentials. External agents authenticate with these keys on every call. Generate one per external agent or team to keep access scoped and revocable. ### Call an agent from code From a parent agent's handler, calling a child agent looks like calling any other tool. The child appears in `agent.tools.list` once it's been added as a dependency in Agent Studio: ```python {3-6} theme={"dark"} from xpander_sdk import Agents parent_agent = Agents().get(agent_id="agt_parent...") result = await parent_agent.ainvoke_tool( tool=parent_agent.tools.get_tool_by_name("call_specialist_agent"), payload={"prompt": "Investigate this incident and return a summary"}, ) print(result.is_success, result.result) ``` What this means in practice: 1. **The child agent runs its full loop.** It has its own tools, instructions, memory, and knowledge bases. The parent only sees the final output as a tool result. 2. **Each agent has its own A2A URL.** External systems (agents on other platforms) can discover and call your agent at `https://a2a.xpander.ai/ag_YOUR_AGENT_ID/` using the A2A protocol. 3. **API keys are per external agent.** Generate a separate key for each external caller so you can revoke access independently. The keys are scoped to the A2A channel; they can't be used to invoke the agent through REST or webhooks. ### Cross-platform delegation The A2A protocol is designed for agents on different platforms to call each other. An agent built on LangChain, AutoGen, or any other A2A-compatible framework can invoke your xpander agent at its A2A URL using a standard A2A request, and vice versa. The Workbench graph view lets you visualize agent relationships across your organization. ## Picking a channel Most agents end up enabling more than one. A common pattern: * **REST** for programmatic access and backend integrations. * **Slack** for the team. * **MCP** for individual developers in their IDE or Claude Desktop. * **Webhooks** for inbound triggers from external systems (GitHub, Stripe, Zapier). * **Cron** for scheduled routine work. * **A2A** for delegation from a manager agent or cross-platform invocation. All channels route through the same `@on_task` handler. There's no per-channel cost in the SDK. ## Things to watch for Channels can collide in subtle ways. A scheduled task that fires every minute while a Slack user is mid-conversation creates two concurrent invocations against the same agent and sometimes the same session. If your handler isn't idempotent, you'll see weird interleavings in the conversation history. Either scope cron tasks to dedicated agents, or design handler logic that tolerates concurrent runs against the same session. ## Next steps Sync, async, and stream endpoints. Full MCP setup walkthrough with screenshots. Full webhook reference with the Workbench tester. Cron-driven invocations. # Agno Source: https://docs.xpander.ai/developers/frameworks/agno The recommended framework path. A few lines to a fully wired agent. [Agno](https://github.com/agno-agi/agno) is the framework xpander.ai has the deepest integration with. In this guide, we'll build a production-ready agent with credentials, instructions, tools, knowledge-base access, session DB, memory, guardrails, and a context-optimization pipeline. ## Prerequisites * **Complete the [Quickstart](/developers/quickstart)** so the CLI, SDK, and `xpander login` are already set up. * **Python 3.12+** for the local handler. * **An LLM provider key in your shell** like `OPENAI_API_KEY`, `ANTHROPIC_API_KEY`. (These keys will only be used locally.) ## 1. Install ```bash theme={"dark"} # Quote the package name so zsh doesn't expand the brackets. pip install "xpander-sdk[agno]" ``` ## 2. Set up scaffolding ```bash theme={"dark"} # Create an agent named "my-first-agent" xpander agent new \ --name "my-first-agent" \ --framework "agno" \ --folder "." ``` These files get created: ``` ./ │ ├── xpander_handler.py # Your @on_task entry point. The file you'll edit most. ├── xpander_config.json # Agent ID, organization ID, API key, framework selection. ├── agent_instructions.json # role / goal / general (the agent's system prompt). ├── requirements.txt # Python dependencies (xpander-sdk[agno] is pinned here). └── .env # XPANDER_API_KEY, XPANDER_ORGANIZATION_ID, XPANDER_AGENT_ID. ``` ### `xpander_config.json` reference ```json xpander_config.json theme={"dark"} { "agent_id": "agt_01H...", "organization_id": "org_01H...", "api_key": "xpd_...", "framework": "agno" } ``` ## 3. Create task handler The full pattern, wrapped in `@on_task` so the platform routes tasks to it: ```python xpander_handler.py highlight={10-11,14,17-21} theme={"dark"} from dotenv import load_dotenv load_dotenv() # loads XPANDER_API_KEY and friends before any sdk import from xpander_sdk import on_task, Task, Backend, Tokens from agno.agent import Agent @on_task async def handler(task: Task) -> Task: # 1. Fetch the agent's full configuration from xpander's control plane. backend = Backend(configuration=task.configuration) agno_args = await backend.aget_args(task=task) # 2. Build the framework's own Agent with that config. agno_agent = Agent(**agno_args, debug_mode=True) # 3. Run the LLM loop with the task's input, files, and images. result = await agno_agent.arun( input=task.to_message(), files=task.get_files(), images=task.get_images(), ) # 4. Write the result back so the platform can store and display it. task.result = result.content task.tokens = Tokens( prompt_tokens=result.metrics.input_tokens, completion_tokens=result.metrics.output_tokens, ) task.used_tools = [t.tool_name for t in (result.tools or [])] return task ``` Here's what's happening: 1. **`Backend(configuration=task.configuration)`** picks up the API key, organization ID, and base URL from the active task. No need to read `.env` directly. 2. **`await backend.aget_args(task=task)`** calls the control plane and returns a dict with the full agent configuration (instructions, tools, model, knowledge bases, session storage, memory, guardrails). Always pass `task=task` inside an `@on_task` handler so task-level overrides (`instructions_override`, `expected_output`, `output_schema`) are merged in. 3. **`Agent(**agno_args, debug_mode=True)`** splats that dict into Agno's own `Agent` class. `debug_mode` prints tool calls and token usage; remove it for production. 4. **`task.to_message()`** flattens the prompt text, file URLs, and any inline-readable file content into a single string ready for Agno. **`task.get_files()`** and **`task.get_images()`** return Agno-typed `agno.media.File` and `agno.media.Image` objects. 5. **Reporting `task.tokens` and `task.used_tools` is optional.** Skipping them just means the metrics view in [Agent Studio](https://chat.xpander.ai) shows "no usage data" for that run. ### `backend.aget_args` reference #### Input parameters `backend.aget_args` accepts these arguments: | Key | Type | Notes | | ---------- | ---------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | `task` | `Task` | The active task inside an `@on_task` handler. Pass it so task-level overrides (`instructions_override`, `expected_output`, `output_schema`) are merged into the resolved args. Required inside `@on_task`; optional in scripts and notebooks where you can pass `agent_id=` instead. | | `override` | `dict` | `dict.update()`-merged onto the resolved args after everything else is built. Accepts any key Agno's `Agent.__init__` takes (see below). Optional. Defaults to `None`. | | `tools` | `list[Callable]` | Appended to the resolved tools list (connectors plus custom plus MCP). Use it to inject ephemeral tools without touching the agent's graph. Optional. Defaults to `[]`. | **What can `override` change?** `override` accepts any key Agno's `Agent.__init__` takes. Two ways to use it: 1. Replace any value the SDK already resolves: any key from the [output-params table](#output-parameters) below (`model`, `instructions`, `tools`, `db`, `knowledge_retriever`, `pre_hooks`, `output_schema`, and so on). 2. Add Agno-native kwargs the SDK doesn't set itself. Common ones: | Key | What it controls | | ----------------- | ------------------------------------- | | `temperature` | Sampling temperature for the model. | | `max_tokens` | Cap on tokens generated per response. | | `show_tool_calls` | Print tool calls during the run. | | `debug_mode` | Print full LLM payloads and timings. | | `use_json_mode` | Force JSON-mode responses. | | `markdown` | Render responses as Markdown. | See the [Agno Agent reference](https://docs.agno.com) for the full surface. Setting `override["model"]` skips the SDK's own model resolution entirely, so use it whenever you want a different model client without re-implementing credential handling. Example using `override` to A/B-test two models against the same agent definition: ```python theme={"dark"} # Run the same agent against a different model for one task. from agno.models.anthropic import Claude args = await backend.aget_args( task=task, override={"model": Claude(id="claude-sonnet-4-5", api_key="...")}, ) ``` Example using `override` to tune Agno-native sampling parameters: ```python theme={"dark"} # Lower temperature and bound max tokens for a deterministic run. args = await backend.aget_args( task=task, override={"temperature": 0.2, "max_tokens": 800}, ) ``` Example using `tools` to inject an ephemeral test tool: ```python theme={"dark"} def _local_clock() -> str: """Return the developer's local clock for debugging.""" from datetime import datetime return datetime.now().isoformat() args = await backend.aget_args(task=task, tools=[_local_clock]) ``` For anything more invasive (a new pre-hook, a different DB), grab the args dict and mutate it directly before splatting into `Agent(...)`. The dict is yours; the SDK won't reach back in. #### Output parameters Calling `backend.aget_args` returns these fields: | Key | Type | Notes | | -------------------------------------------------------------------------------------------------------------------------------- | --------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `id` | `str` | Agent ID from `xpander_config.json`. Always set. | | `name` | `str` | Agent name from the control plane. Always set. | | `description` | `str` | Sourced from `agent_instructions.json` `general`. Always set. | | `model` | `agno.models.base.Model` | Instantiated with credentials resolved. The agent's custom LLM key wins on cloud, your shell env var wins locally. Always set. | | `instructions` | `str` | The Agent Studio instructions (or `task.instructions_override`), with context-optimization, workspace-output, and compact-tool guidance appended. Always set. | | `tools` | `list[Callable]` | Connectors, custom `@register_tool` functions, MCP servers (with OAuth handled), `xpcompact_context`, plus Agno's `think` / `analyze` when `reasoning_tools_enabled=True`. Always set. | | `tool_hooks` | `list[Callable]` | One internal hook for retries on transient errors, stuck-loop detection, activity reporting, and Layer 1 microcompaction. Append to it, don't replace. Always set. | | `compression_manager` | `XPanderContextOptimizer` | Layered context-optimization pipeline (microcompaction, auto-compaction, manual via `xpcompact_context`, emergency, pre-retry). Always set. | | `add_datetime_to_context` | `bool` | Inject the current datetime into context on every run. Always set. Defaults to `True`. | | `store_events` | `bool` | Persist Agno run events. Always set. Defaults to `True`. | | `db` | `AsyncPostgresDb` or `PostgresDb` | Scoped to a per-agent schema. Set when `session_storage`, `user_memories`, or `agent_memories` is on. | | `add_history_to_context`, `session_id`, `user_id`, `num_history_runs`, `max_tool_calls_from_history`, `enable_session_summaries` | various | Driven by `agno_settings.session_storage` (see settings table below). Set when `session_storage=True`. | | `enable_user_memories`, `memory_manager`, `enable_agentic_memory` | various | Per-user facts that persist across sessions. Set when `user_memories=True`. | | `add_culture_to_context`, `update_cultural_knowledge`, `enable_agentic_culture` | `bool` | Org-wide facts. Single-agent only (skipped on Teams). Set when `agent_memories=True`. | | `learning` | `bool` | Set when `agno_settings.learning=True`. | | `tool_call_limit` | `int` | Cap on tool calls per run. Set when configured on the agent. | | `knowledge_retriever`, `search_knowledge` | callable, `bool` | Agno calls the retriever automatically during the loop. Set when KBs are attached. | | `pre_hooks` | `list` | `PIIDetectionGuardrail`, `PromptInjectionGuardrail`, `OpenAIModerationGuardrail` per `agno_settings`. Set when guardrails are on. | | `output_schema`, `use_json_mode`, `markdown` | various | Structured output and Markdown formatting. Task-level output format and schema overrides applied. Set per output settings. | | `expected_output`, `additional_context` | `str` | Forwarded from the agent definition and task. Set when present. | | `members`, `add_member_tools_to_context`, `share_member_interactions`, `show_members_responses` | various | The SDK recursively builds each sub-agent as `AgnoAgent` or `AgnoTeam`. Set when `agent.is_a_team`. | ## 4. Edit the agent's system prompt `agent_instructions.json` contains the agent's system prompt and has exactly three fields: ```json agent_instructions.json theme={"dark"} { "role": [ "You are a customer support assistant for Acme.", "Always confirm the customer's account ID before taking any action." ], "goal": [ "Resolve the customer's issue in as few turns as possible.", "Escalate to a human if the request involves a refund over $500." ], "general": "Be concise, professional, and friendly. Never invent policy details; if you don't know something, say so and offer to escalate." } ``` Save the file and the next `xpander agent dev` syncs it to the control plane. ## 5. Set up streaming (optional) For token-by-token output, decorate an `async def` that yields `TaskUpdateEvent` objects instead of returning a `Task`. The decorator detects the difference automatically. ```python streaming_handler.py highlight={13-29} theme={"dark"} from datetime import datetime, timezone from xpander_sdk import on_task, Task, Backend, TaskUpdateEvent, TaskUpdateEventType from agno.agent import Agent from agno.run.agent import RunEvent, RunOutput @on_task async def handler(task: Task): backend = Backend(configuration=task.configuration) agno_agent = Agent(**(await backend.aget_args(task=task))) final_output = None # Agno emits a stream of events: chunks, tool calls, final RunOutput. async for event in await agno_agent.arun( input=task.to_message(), stream=True, stream_events=True, yield_run_output=True, ): if isinstance(event, RunOutput): final_output = event elif hasattr(event, "event") and event.event == RunEvent.run_content and event.content: # Forward each token chunk to the platform's SSE stream. yield TaskUpdateEvent( type=TaskUpdateEventType.Chunk, task_id=task.id, organization_id=task.organization_id, time=datetime.now(timezone.utc), data=event.content, ) task.result = final_output.content if final_output else "" yield TaskUpdateEvent( type=TaskUpdateEventType.TaskFinished, task_id=task.id, organization_id=task.organization_id, time=datetime.now(timezone.utc), data=task, ) ``` Here's what's happening: 1. **`stream=True, stream_events=True, yield_run_output=True`** tell Agno to emit events instead of buffering. The handler receives chunks, tool-call events, and a final `RunOutput`. 2. **The `Chunk` event** forwards each token to the platform's SSE stream so clients render output as it arrives. 3. **The `TaskFinished` event** signals the end of the stream and carries the final task back to the platform. A streaming handler exposes itself only through `POST /invoke`, returning Server-Sent Events. The platform's SSE listener for cloud-deployed agents expects a regular handler that returns a `Task`. So if you need both an interactive streaming experience and platform-routed tasks, run two handlers, or have your streaming endpoint proxy through a regular handler. ## 6. Test local development Run the handler with the dev server. Tasks created from any channel (REST, Slack, Agent Studio) route to your laptop: ```bash theme={"dark"} # Starts the @on_task HTTP server and subscribes to the platform event stream. xpander agent dev ``` **Routing cloud traffic to a local instance is a preview feature.** When a local instance is running via `xpander agent dev`, it takes over and all tasks route to your locally running agent instead. Only one can be active at a time. For one-shot testing without a server: ```bash theme={"dark"} # Calls your handler exactly once with the given prompt and exits. python3 xpander_handler.py \ --invoke \ --prompt "Quick test" \ --output_format json \ --output_schema '{"answer":"string"}' ``` `--output_format` and `--output_schema` are useful for testing structured output without changing the agent's settings in the control plane. ## Troubleshooting `Backend.aget_args()` reads `task.instructions_override` while building the args. Inside an `@on_task` handler, always pass the active task: `await backend.aget_args(task=task)`. The `agent_id`-only form is supported outside a handler (in scripts and notebooks), but inside one the active task is the source of truth for instruction overrides. Session storage is on by default, so the args dict includes a `db` wired to xpander's Postgres. For cloud-hosted agents this is automatic. For self-hosted or air-gapped deployments, the database needs to be reachable from where the agent runs. Check the connection string with `await agent.aget_connection_string()` and confirm the host is reachable. To turn session storage off, flip `agno_settings.session_storage` to `False` in [Agent Studio](https://chat.xpander.ai). Custom LLM keys configured on the agent take precedence on cloud deployments. Locally, your shell's `OPENAI_API_KEY` (or the equivalent for your provider) wins. If you want the cloud-side custom key locally too, mirror it into your `.env`. zsh expands the brackets. Quote the package name: `pip install "xpander-sdk[agno]"`. ## Next steps The 10-minute scaffold-to-run walkthrough that produced the handler shown above. Wrap private APIs as tools with `@register_tool` and pass them through the args dict. The deep dive on `session_storage`, user memories, and agent memories. The SDK class names mapped onto agents, tasks, threads, and memory. What's auto-wired vs. manual for Agno, OpenAI Agents SDK, LangChain, and AWS Strands. # AWS Strands Source: https://docs.xpander.ai/developers/frameworks/aws-strands Use xpander tools and instructions inside the AWS Strands agent [AWS Strands](https://github.com/strands-agents/sdk-python) is the agent framework from AWS for orchestrating tool-using LLMs. It ships a small `Agent` class with first-class Bedrock support and a callable run interface. xpander.ai supplies the agent's identity (instructions, tools, model, knowledge bases); this page wires the two together. In this guide, we'll build an agent that runs on a native `strands.Agent`, with its instructions, tools, and model all coming from xpander. ## What doesn't come built in Unlike the Agno path, Strands doesn't have a one-call shortcut for pulling everything in at once, so we grab the agent definition from xpander and hand the pieces to Strands ourselves. It's only a few extra lines, but a few capabilities aren't auto-wired and you wire them yourself: | Capability | How to wire it | | ------------------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | Knowledge-base retrieval | Wrap `xpander_agent.knowledge_bases_retriever()` in a `@strands.tool` and concatenate it onto `strands_tools`. Full example in [step 5](#5-wire-knowledge-base-retrieval-optional). | | Session storage | Strands has no Postgres-backed store. Use Strands' own `SessionManager` and `conversation_manager` for in-process history, or move to the [Agno integration](/developers/frameworks/agno) for a managed store. | | Guardrails | Implement as pre-checks before `invoke_async`, or as Strands `hooks` on the `Agent`. Agno's PII / prompt-injection / OpenAI-moderation pre-hooks don't apply here. | ## Prerequisites * **Complete the [Quickstart](/developers/quickstart)** so the CLI, SDK, and `xpander login` are already set up. * **Python 3.12+** for the local handler. * **AWS credentials in your shell** (`AWS_ACCESS_KEY_ID`, `AWS_SECRET_ACCESS_KEY`, `AWS_REGION`, or an instance profile). Strands defaults to AWS Bedrock when `model=` is a string. If you wire a non-Bedrock client instead, an alternate provider key (`OPENAI_API_KEY`, `ANTHROPIC_API_KEY`) takes its place. Strands does not pick up the LLM credentials configured on the agent in [Agent Studio](https://chat.xpander.ai); if you've set a custom key on the agent, mirror it into your `.env` so the runner uses it. ## 1. Install Both packages are required. Strands ships under the `strands-agents` distribution but imports as `strands`. ```bash theme={"dark"} # 1. xpander runtime (provides the strands_tools adapter property). pip install xpander-sdk # 2. AWS Strands itself (imported as `strands`). pip install strands-agents ``` ## 2. Set up scaffolding ```bash theme={"dark"} # Create an agent named "my-first-agent" xpander agent new \ --name "my-first-agent" \ --framework "strands-agents" \ --folder "." ``` These files get created: ``` ./ │ ├── xpander_handler.py # Your @on_task entry point. The file you'll edit most. ├── xpander_config.json # Agent ID, organization ID, API key, framework selection. ├── agent_instructions.json # role / goal / general (the agent's system prompt). ├── requirements.txt # Python dependencies (xpander-sdk and strands-agents pinned here). └── .env # XPANDER_API_KEY, XPANDER_ORGANIZATION_ID, XPANDER_AGENT_ID. ``` ### `xpander_config.json` reference ```json xpander_config.json theme={"dark"} { "agent_id": "agt_01H...", "organization_id": "org_01H...", "api_key": "xpd_...", "framework": "strands-agents" } ``` ## 3. Create task handler The full pattern, wrapped in `@on_task` so the platform routes tasks to it. The highlighted lines are the integration's load-bearing reads: ```python xpander_handler.py highlight={10-12,15-21,24} theme={"dark"} from dotenv import load_dotenv load_dotenv() # loads XPANDER_API_KEY, AWS_ACCESS_KEY_ID, etc. before any sdk import from xpander_sdk import on_task, Task, Agents from strands import Agent as StrandsAgent @on_task async def handler(task: Task) -> Task: # 1. Load the xpander agent (instructions, tools, model are all on it). xpander_agent = await Agents(configuration=task.configuration).aget( agent_id=task.agent_id, ) # 2. Build the Strands Agent from xpander fields. Strands wraps a model-id # string as BedrockModel(model_id=...) automatically. native = StrandsAgent( name=xpander_agent.name, description=xpander_agent.instructions.description, system_prompt=xpander_agent.instructions.full, tools=xpander_agent.strands_tools, model=xpander_agent.model_name, ) # 3. Run the LLM loop with the task's user message. result = await native.invoke_async(task.to_message()) # 4. Write the result back so the platform can store and display it. # str(result) concatenates the text blocks from result.message. task.result = str(result) return task ``` Here's what's happening: 1. **`Agents(configuration=task.configuration).aget(agent_id=task.agent_id)`** calls the xpander control plane and returns a fully-hydrated `Agent` object. Its instructions, tool repository, model, and knowledge-base links are all populated. 2. **`xpander_agent.instructions.full`** is a single string that wraps the agent's `general` description, `role` list, and `goal` list in ``, ``, and `` tags. Drop it straight into Strands' `system_prompt=` kwarg (note the kwarg name; it isn't `instructions=`). 3. **`xpander_agent.strands_tools`** is a computed property that wraps every xpander tool (connectors, custom `@register_tool` functions, MCP tools) with `@strands.tool`. Each wrapper's underlying callable invokes xpander's tool execution path, so connector auth, observability, and retries still work. 4. **`xpander_agent.model_name`** is the model identifier configured on the agent (e.g. `anthropic.claude-sonnet-4-5-20250929-v1:0`, `gpt-4o`). Strands wraps a string as `BedrockModel(model_id=...)` automatically. For non-Bedrock providers, swap in an explicit model client (see the [Troubleshooting](#troubleshooting) section). 5. **`native.invoke_async(task.to_message())`** drives the LLM loop. `task.to_message()` returns the task's user message in the shape Strands expects. 6. **Writing back to `task.result`** lets xpander store the output and surface it in the API, Agent Studio, and any wired channels. `str(result)` concatenates the text blocks from `result.message` into a single string. ## 4. Edit the agent's system prompt `agent_instructions.json` contains the agent's system prompt and has exactly three fields: ```json agent_instructions.json theme={"dark"} { "role": [ "You are a customer support assistant for Acme.", "Always confirm the customer's account ID before taking any action." ], "goal": [ "Resolve the customer's issue in as few turns as possible.", "Escalate to a human if the request involves a refund over $500." ], "general": "Be concise, professional, and friendly. Never invent policy details; if you don't know something, say so and offer to escalate." } ``` Save the file and the next `xpander agent dev` syncs it to the control plane. `general` is also exposed as `xpander_agent.instructions.description`, which the handler passes to Strands' `description=` kwarg so other agents that wrap this one as a tool see the right summary. ## 5. Wire knowledge-base retrieval (optional) Strands doesn't auto-wire xpander's knowledge bases, so expose the retriever as a `@strands.tool` the agent can call. The highlighted lines show the two integration points: building the retriever and concatenating it onto the auto-wired tool list. ```python xpander_handler.py highlight={4,13} theme={"dark"} from strands import Agent as StrandsAgent, tool @tool def search_knowledge_base(query: str, num_documents: int = 5) -> list[dict]: """Search the agent's linked knowledge bases. Returns top-k matching documents.""" # knowledge_bases_retriever() returns a callable: (query, agent=None, num_documents=5, **kwargs) retriever = xpander_agent.knowledge_bases_retriever() return retriever(query=query, num_documents=num_documents) native = StrandsAgent( name=xpander_agent.name, description=xpander_agent.instructions.description, system_prompt=xpander_agent.instructions.full, # Concatenate the auto-wired tools with the KB retriever. tools=[*xpander_agent.strands_tools, search_knowledge_base], model=xpander_agent.model_name, ) ``` The retriever runs concurrent searches across every linked KB and returns the top N results by score. ## 6. Set up streaming (optional) For token-by-token output, decorate an `async def` that yields `TaskUpdateEvent` objects instead of returning a `Task`. The decorator detects the difference automatically. Strands exposes `agent.stream_async(...)`, which yields a sequence of dict events; text deltas arrive on events that carry a `"data"` key. ```python streaming_handler.py highlight={17-23,26-32} theme={"dark"} from datetime import datetime, timezone from xpander_sdk import on_task, Task, Agents, TaskUpdateEvent, TaskUpdateEventType from strands import Agent as StrandsAgent @on_task async def handler(task: Task): xpander_agent = await Agents(configuration=task.configuration).aget(agent_id=task.agent_id) native = StrandsAgent( name=xpander_agent.name, description=xpander_agent.instructions.description, system_prompt=xpander_agent.instructions.full, tools=xpander_agent.strands_tools, model=xpander_agent.model_name, ) final_output = "" # stream_async yields dict events: text deltas carry a "data" key, # tool calls and tool results carry their own keys. async for event in native.stream_async(task.to_message()): chunk = event.get("data") if isinstance(event, dict) else None if not chunk: continue final_output += chunk # Forward each text delta to the platform's SSE stream. yield TaskUpdateEvent( type=TaskUpdateEventType.Chunk, task_id=task.id, organization_id=task.organization_id, time=datetime.now(timezone.utc), data=chunk, ) task.result = final_output yield TaskUpdateEvent( type=TaskUpdateEventType.TaskFinished, task_id=task.id, organization_id=task.organization_id, time=datetime.now(timezone.utc), data=task, ) ``` Here's what's happening: 1. **`native.stream_async(task.to_message())`** returns an async iterator. Each event is a dict; text deltas carry a `"data"` key, tool-use events carry `"current_tool_use"`, and a final completion event carries the `AgentResult` under `"result"`. 2. **The `Chunk` event** forwards each text delta to the platform's SSE stream so clients render output as it arrives. 3. **The `TaskFinished` event** signals the end of the stream and carries the final task back to the platform. A streaming handler exposes itself only through `POST /invoke`, returning Server-Sent Events. The platform's SSE listener for cloud-deployed agents expects a regular handler that returns a `Task`. So if you need both an interactive streaming experience and platform-routed tasks, run two handlers, or have your streaming endpoint proxy through a regular handler. ## 7. Test local development Run the handler with the dev server. Tasks created from any channel (REST, Slack, Agent Studio) route to your laptop: ```bash theme={"dark"} # Starts the @on_task HTTP server and subscribes to the platform event stream. xpander agent dev ``` **Routing cloud traffic to a local instance is a preview feature.** When a local instance is running via `xpander agent dev`, it takes over and all tasks route to your locally running agent instead. Only one can be active at a time. For one-shot testing without a server: ```bash theme={"dark"} # Calls your handler exactly once with the given prompt and exits. python3 xpander_handler.py \ --invoke \ --prompt "Quick test" \ --output_format json \ --output_schema '{"answer":"string"}' ``` `--output_format` and `--output_schema` are useful for testing structured output without changing the agent's settings in the control plane. ## Troubleshooting `Backend.aget_args()` currently dispatches only to the Agno builder and raises `NotImplementedError` for any other framework. For Strands, you load the Agent yourself with `Agents().aget(...)` and read the fields you need (instructions, tools, model name) onto Strands' `Agent` constructor. Strands names the system-prompt kwarg `system_prompt=`, not `instructions=`. Pass `system_prompt=xpander_agent.instructions.full` to the `Agent` constructor. The xpander side reads from `instructions` (the Pydantic field on the SDK's `Agent`); the Strands side accepts `system_prompt`. The two are not the same kwarg. Strands wraps a string `model=` as `BedrockModel(model_id=...)` and the underlying `boto3` client reads standard AWS credentials (`AWS_ACCESS_KEY_ID`, `AWS_SECRET_ACCESS_KEY`, `AWS_REGION`, or an instance profile). It does not pick up a custom LLM key configured on the agent in [Agent Studio](https://chat.xpander.ai). If the runner can't authenticate or hits the wrong region, set the AWS env vars in your local `.env` and confirm the model ID is enabled in that region's Bedrock model catalog. Pass an explicit Strands model client instead of a string: ```python theme={"dark"} from strands.models.openai import OpenAIModel native = StrandsAgent( name=xpander_agent.name, description=xpander_agent.instructions.description, system_prompt=xpander_agent.instructions.full, tools=xpander_agent.strands_tools, model=OpenAIModel( client_args={"api_key": "sk-..."}, model_id=xpander_agent.model_name, ), ) ``` The xpander tools layer is provider-agnostic. The underlying model has to support tool calling for the integration to work end to end. Strands has its own `SessionManager` and `conversation_manager` for in-process history. For durable cross-process state, use Strands' built-in session managers (or a custom one), or switch to the [Agno integration](/developers/frameworks/agno) for an auto-wired Postgres store. The convenience helpers `xpander_agent.get_user_sessions()` and `xpander_agent.get_session()` raise `NotImplementedError` outside Agno. The `strands_tools` wrapper's input schema is `{"payload": }`, so the LLM is asked to nest its tool arguments under `payload`. This mirrors how xpander stores connector schemas internally and keeps the same shape across every framework adapter. You don't need to do anything in your handler; the wrapper unpacks `payload` before invoking the tool. ## Next steps The 10-minute scaffold-to-deploy walkthrough that produced the handler shown above. Wrap private APIs as tools with `@register_tool` and ship them through `strands_tools`. What you'd gain by switching: session storage, knowledge-base auto-wiring, `Backend.aget_args()`. The SDK class names mapped onto agents, tasks, threads, and memory. What's auto-wired vs. manual for Agno, OpenAI Agents SDK, LangChain, and AWS Strands. # Frameworks Source: https://docs.xpander.ai/developers/frameworks/index Pick a framework and see what xpander wires up for you Xpander supplies your agent's identity (instructions, tools, knowledge bases, memory, deployment target) and routes tasks to your handler. The **framework** you choose is the library that runs the LLM loop in your process: the thing with an `Agent` class, a tool-calling interface, and an `arun()` method. xpander does not replace your framework. It plugs into it. Selection lives in `xpander_config.json`, written by `xpander agent new`. The SDK reads `framework` from that file and wires up accordingly: ```json xpander_config.json theme={"dark"} { "agent_id": "agt_01H...", "organization_id": "org_01H...", "api_key": "xpd_...", "framework": "agno" // or: "open-ai-agents", "langchain", "strands-agents" } ``` Right now, the SDK supports 4 frameworks: Agno OpenAI Agents SDK LangChain + LangGraph AWS Strands ## Comparison | Capability | Agno | OpenAI Agents SDK | LangChain | AWS Strands | | ------------------------------------------------- | ----------------------- | ---------------------------------------------- | ----------------------------------------- | ----------------------------------------- | | Pre-built connectors (2,000+) | Auto-included | `agent.openai_agents_sdk_tools` | `agent.tools.functions` | `agent.strands_tools` | | Custom `@register_tool` functions | Auto-included | Auto-included | Auto-included | Auto-included | | Instructions (role, goal, general) | Auto-attached | `agent.instructions.full` | `agent.instructions.full` | `agent.instructions.full` | | Model + provider credentials | Auto-attached | `agent.model_name` (you build the client) | `agent.model_name` (you build the client) | `agent.model_name` (you build the client) | | Knowledge-base retriever | Auto-attached | Manual via `agent.knowledge_bases_retriever()` | Manual | Manual | | Session storage (Postgres) | Auto-wired | Manual | Manual | Manual | | User and agent memory | Auto-wired | Manual | Manual | Manual | | Context optimization (toon encoding, compaction) | Auto-wired | Not available | Not available | Not available | | Guardrails (PII, prompt injection, moderation) | Auto-wired | Manual | Manual | Manual | | Multi-agent teams | Auto-wired (`AgnoTeam`) | Manual | Manual | Manual | | Session helpers (`agent.get_user_sessions`, etc.) | Yes | Raises `NotImplementedError` | Raises `NotImplementedError` | Raises `NotImplementedError` | A few takeaways worth calling out: * **Agno is the only path with automatic wiring.** `Backend.aget_args()` dispatches on `agent.framework`. On the other three, you load the agent through `Agents().aget(...)` and read fields off it yourself. * **Pre-built connectors and custom `@register_tool` functions reach every framework.** What changes is the property name you read them from: `agent.tools.functions` for LangChain, `agent.openai_agents_sdk_tools` for the OpenAI Agents SDK, `agent.strands_tools` for AWS Strands. * **Memory, knowledge retrieval, and guardrails are Agno-only auto-wired.** On other frameworks, xpander gives you the data (`agent.knowledge_bases_retriever()`, session metadata, the agent's memory config) but your code is responsible for plugging it into the framework. * **Agno-exclusive features**: context optimization (toon encoding, runtime compaction), `AgnoTeam`-based multi-agent coordination, and the session helpers (`agent.get_user_sessions`, `agent.get_session`, `agent.delete_session`, which raise `NotImplementedError` outside Agno). See the framework's dedicated page for the full guide. ## How to choose Default to Agno unless you have a reason not to. Pick a non-Agno framework when: * **Existing investment.** Your team already builds on it and switching cost is real. Example: a LangGraph workflow that's been in production for six months. * **Framework-specific feature.** You need something Agno doesn't have. Example: LangGraph's stateful multi-step workflows, the OpenAI Agents SDK's `Runner` ergonomics, Strands' AWS-native primitives. * **Embedded in an existing app.** You're adding xpander tools to a service that already runs one of these frameworks. Example: a FastAPI worker that already imports `agents.Runner`. You're not locked in. The agent's identity lives in xpander's control plane, so you can swap frameworks later by editing `framework` in `xpander_config.json` and rewriting your handler. ## Next steps The recommended path. What `Backend.aget_args()` actually wires up. Manual wiring with `agent.openai_agents_sdk_tools`. Manual wiring with `agent.tools.functions` and `create_react_agent`. Manual wiring with `agent.strands_tools` on AWS-native orchestration. The SDK class names mapped onto agents, tasks, threads, tools, and memory. 10-minute scaffold-to-deploy walkthrough on the default Agno path. # LangChain + LangGraph Source: https://docs.xpander.ai/developers/frameworks/langchain Bind xpander tools to a LangGraph ReAct agent [LangChain](https://www.langchain.com/) and [LangGraph](https://langchain-ai.github.io/langgraph/) let you build custom tool-calling and graph-based agent runtimes. xpander.ai supplies the agent definition (instructions, tools, model, knowledge-base links), and your handler wires those fields into a native LangGraph flow. In this guide, we'll build an agent that runs on a native LangGraph ReAct loop, with its tools, model, and instructions all coming from xpander. ## What doesn't come built in Unlike the Agno path, LangChain doesn't have a one-call shortcut for pulling everything in at once, so we grab the agent definition from xpander and pass the pieces into `create_react_agent` ourselves. It's only a few extra lines, but a few capabilities aren't auto-wired and you wire them in your graph: | Capability | How to wire it | | ---------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | Knowledge-base retrieval | Call `xpander_agent.knowledge_bases_retriever()` and expose it as a LangChain tool (or call it directly inside a node). | | Session storage | Use LangGraph's own checkpointer/state flow, or move to [Agno](/developers/frameworks/agno) if you want the managed session-storage path from `Backend.aget_args()`. | | Automatic guardrails, context-optimization plumbing, and multi-agent team runtime wiring | Build those behaviors yourself in your graph, or switch to [Agno](/developers/frameworks/agno). | ## Prerequisites * **Complete the [Quickstart](/developers/quickstart).** You should already have the CLI installed, `xpander login` completed, and a scaffolded agent project. * **Python 3.12+** for local development. * **An LLM provider key in your shell** that matches your LangChain provider package. For example: `OPENAI_API_KEY` for `langchain-openai`, `ANTHROPIC_API_KEY` for `langchain-anthropic`. ## 1. Install All packages below are required for the default OpenAI example. ```bash theme={"dark"} # 1. Install xpander runtime and LangChain/LangGraph dependencies. pip install \ xpander-sdk \ langchain \ langchain-openai \ langgraph \ python-dotenv # 2. Optional: swap provider package for your model vendor. pip install langchain-anthropic pip install langchain-ollama ``` ## 2. Set up scaffolding ```bash theme={"dark"} # Create an agent named "my-langchain-agent" xpander agent new \ --name "my-langchain-agent" \ --framework "langchain" \ --folder "." ``` These files get created: ``` ./ │ ├── xpander_handler.py # Your @on_task entry point. The file you'll edit most. ├── xpander_config.json # Agent ID, organization ID, API key, framework selection. ├── agent_instructions.json # role / goal / general (the agent's system prompt). ├── requirements.txt # Python dependencies. └── .env # XPANDER_API_KEY, XPANDER_ORGANIZATION_ID, XPANDER_AGENT_ID. ``` ### `xpander_config.json` reference ```json xpander_config.json theme={"dark"} { "agent_id": "agt_01H...", "organization_id": "org_01H...", "api_key": "xpd_...", "framework": "langchain" } ``` ## 3. Create task handler The full pattern, wrapped in `@on_task` so the platform routes tasks to it: ```python xpander_handler.py highlight={25,28,31,34-39,43} theme={"dark"} from dotenv import load_dotenv load_dotenv() from xpander_sdk import on_task, Task, Agents from langchain_openai import ChatOpenAI from langgraph.prebuilt import create_react_agent def system_prompt(instructions): # xpander instructions are structured (role, goal, general). # LangChain expects one system string. parts = [] if instructions.general: parts.append(f"System: {instructions.general}") if instructions.goal_str: parts.append(f"Goals:\n{instructions.goal_str}") if instructions.role: parts.append("Instructions:\n" + "\n".join(f"- {r}" for r in instructions.role)) return "\n\n".join(parts) @on_task async def handler(task: Task) -> Task: # 1. Load the agent definition from xpander. xpander_agent = await Agents(configuration=task.configuration).aget(agent_id=task.agent_id) # 2. Build a LangChain chat model from the configured model name. llm = ChatOpenAI(model=xpander_agent.model_name, temperature=0) # 3. Bind xpander tools as LangGraph-compatible callables. react_agent = create_react_agent(llm, xpander_agent.tools.functions) # 4. Run the ReAct loop. response = await react_agent.ainvoke({ "messages": [ ("system", system_prompt(xpander_agent.instructions)), ("user", task.to_message()), ] }) # 5. Write result back so xpander can persist and display it. last = response["messages"][-1] task.result = last.content if hasattr(last, "content") else str(last) return task ``` Here's what's happening: 1. **`Agents(...).aget(agent_id=task.agent_id)`** returns a fully loaded agent object. 2. **`xpander_agent.model_name`** is used as the LLM model id in your LangChain client. 3. **`xpander_agent.tools.functions`** returns one callable per tool, with a `payload` schema signature and generated docstrings LangChain/LangGraph can use. 4. **`xpander_agent.instructions`** contains `general`, `role`, and `goal` fields so you can build the system prompt format your graph expects. 5. **`task.result = ...`** hands the output back to xpander for storage and UI/API visibility. ## 4. Edit the agent system prompt `agent_instructions.json` contains the agent's system prompt and maps directly to `agent.instructions` in code: ```json agent_instructions.json theme={"dark"} { "role": [ "You are a customer support assistant for Acme.", "Always confirm the customer's account ID before taking any action." ], "goal": [ "Resolve the customer's issue in as few turns as possible.", "Escalate to a human if the request involves a refund over $500." ], "general": "Be concise, professional, and friendly. Never invent policy details; if you don't know something, say so and offer to escalate." } ``` Save the file and the next `xpander agent dev` syncs it to the control plane. ## 5. Stream chunks from LangGraph (optional) For streaming output, use an async generator handler that yields `TaskUpdateEvent` values: ```python xpander_handler.py (streaming variant) expandable theme={"dark"} from datetime import datetime, timezone from xpander_sdk import on_task, Task, Agents, TaskUpdateEvent, TaskUpdateEventType from langchain_openai import ChatOpenAI from langgraph.prebuilt import create_react_agent @on_task async def handler(task: Task): xpander_agent = await Agents(configuration=task.configuration).aget(agent_id=task.agent_id) llm = ChatOpenAI(model=xpander_agent.model_name, temperature=0) react_agent = create_react_agent(llm, xpander_agent.tools.functions) messages = [ ("system", system_prompt(xpander_agent.instructions)), ("user", task.to_message()), ] final_content = "" async for chunk in react_agent.astream({"messages": messages}): if "agent" in chunk: for msg in chunk["agent"].get("messages", []): if hasattr(msg, "content") and msg.content: final_content = msg.content yield TaskUpdateEvent( type=TaskUpdateEventType.Chunk, task_id=task.id, organization_id=task.organization_id, time=datetime.now(timezone.utc), data=msg.content, ) task.result = final_content yield TaskUpdateEvent( type=TaskUpdateEventType.TaskFinished, task_id=task.id, organization_id=task.organization_id, time=datetime.now(timezone.utc), data=task, ) ``` This pattern is for the decorator's streaming mode, which is served through `POST /invoke` as SSE output. ## 6. Filter tool outputs with schema enforcement (optional) When a tool returns large payloads, configure output schema filtering in [Agent Studio](https://chat.xpander.ai) for that tool. This keeps only relevant fields and reduces token usage before results are handed back to your LangChain loop. ## 7. Test local development Run the handler with the dev server. Tasks created from any channel (REST, Slack, Agent Studio) route to your laptop: ```bash theme={"dark"} # Starts the @on_task HTTP server and subscribes to the platform event stream. xpander agent dev ``` **Routing cloud traffic to a local instance is a preview feature.** When a local instance is running via `xpander agent dev`, it takes over and all tasks route to your locally running agent instead. Only one can be active at a time. For one-shot testing without a server: ```bash theme={"dark"} # Calls your handler once and exits. python3 xpander_handler.py \ --invoke \ --prompt "Quick test" \ --output_format json \ --output_schema '{"answer":"string"}' ``` `--output_format` and `--output_schema` are useful for testing structured output without changing the agent's settings in the control plane. ## Next steps What goes into `agent.tools.functions`, and how connectors authenticate. Wrap a private API as a tool with `@register_tool`. A standalone runnable script you can copy. What is auto-wired vs. manual for each supported framework. # OpenAI Agents SDK Source: https://docs.xpander.ai/developers/frameworks/openai-agents Use xpander tools and instructions inside the OpenAI Agents runner The [OpenAI Agents SDK](https://github.com/openai/openai-agents-python) is OpenAI's lightweight framework for building tool-using agents. It gives you a small `Agent` class plus a `Runner` that drives the LLM loop. xpander.ai supplies the agent's identity (instructions, tools, model, knowledge bases); this page wires the two together. In this guide, we'll create an xpander Agent with OpenAI Agents SDK. ## What doesn't come built in Unlike Agno, some capabilities aren't auto-wired. Configure them yourself: | Capability | How to wire it | | ------------------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | Knowledge-base retrieval | Wrap `xpander_agent.knowledge_bases_retriever()` in a `@function_tool` and concatenate it onto `openai_agents_sdk_tools`. Full example in [step 5](#5-wire-knowledge-base-retrieval-optional). | | Session storage | The OpenAI Agents SDK has no Postgres-backed store. Persist `result.to_input_list()` between turns and pass it back as `input=previous_items + new_message` on the next run, or move to the [Agno integration](/developers/frameworks/agno) for a managed store. | | Guardrails | Implement as pre-checks before `Runner.run`, or use the OpenAI Agents SDK's own `input_guardrails` parameter on `Agent`. Agno's PII / prompt-injection / OpenAI-moderation pre-hooks don't apply here. | ## Prerequisites * **Complete the [Quickstart](/developers/quickstart)** so the CLI, SDK, and `xpander login` are already set up. * **Python 3.12+** for the local handler. * **`OPENAI_API_KEY` in your shell.** The OpenAI Agents SDK uses its own OpenAI client and does not pick up the LLM credentials configured on the agent in [Agent Studio](https://chat.xpander.ai). If you've set a custom key on the agent, mirror it into your `.env` so the runner uses it. ## 1. Install Both packages are required. The OpenAI Agents SDK ships under the `openai-agents` distribution but imports as `agents`. ```bash theme={"dark"} # 1. xpander runtime (provides the openai_agents_sdk_tools adapter property). pip install xpander-sdk # 2. OpenAI Agents SDK itself (imported as `agents`). pip install openai-agents ``` ## 2. Set up scaffolding ```bash theme={"dark"} # Create an agent named "my-first-agent" xpander agent new \ --name "my-first-agent" \ --framework "open-ai-agents" \ --folder "." ``` These files get created: ``` ./ │ ├── xpander_handler.py # Your @on_task entry point. The file you'll edit most. ├── xpander_config.json # Agent ID, organization ID, API key, framework selection. ├── agent_instructions.json # role / goal / general (the agent's system prompt). ├── requirements.txt # Python dependencies (xpander-sdk and openai-agents pinned here). └── .env # XPANDER_API_KEY, XPANDER_ORGANIZATION_ID, XPANDER_AGENT_ID. ``` ### `xpander_config.json` reference ```json xpander_config.json theme={"dark"} { "agent_id": "agt_01H...", "organization_id": "org_01H...", "api_key": "xpd_...", "framework": "open-ai-agents" } ``` ## 3. Create task handler The full pattern, wrapped in `@on_task` so the platform routes tasks to it. The highlighted lines are the integration's load-bearing reads: ```python xpander_handler.py highlight={10-12,15-20,23} theme={"dark"} from dotenv import load_dotenv load_dotenv() # loads XPANDER_API_KEY, OPENAI_API_KEY, etc. before any sdk import from xpander_sdk import on_task, Task, Agents from agents import Agent as OpenAIAgent, Runner @on_task async def handler(task: Task) -> Task: # 1. Load the xpander agent (instructions, tools, model are all on it). xpander_agent = await Agents(configuration=task.configuration).aget( agent_id=task.agent_id, ) # 2. Build the OpenAI Agents SDK's own Agent from three xpander fields. native = OpenAIAgent( name=xpander_agent.name, instructions=xpander_agent.instructions.full, tools=xpander_agent.openai_agents_sdk_tools, model=xpander_agent.model_name, ) # 3. Run the LLM loop with the task's user message. result = await Runner.run(native, input=task.to_message()) # 4. Write the result back so the platform can store and display it. task.result = result.final_output return task ``` Here's what's happening: 1. **`Agents(configuration=...).aget(agent_id=...)`** calls the xpander control plane and returns a fully-hydrated `Agent` object. Its instructions, tool repository, model, and knowledge-base links are all populated. 2. **`xpander_agent.instructions.full`** is a single string that wraps the agent's `general` description, `role` list, and `goal` list in ``, ``, and `` tags. Drop it straight into the OpenAI Agents SDK's `instructions` parameter. 3. **`xpander_agent.openai_agents_sdk_tools`** is a computed property that wraps every xpander tool (connectors, custom `@register_tool` functions, MCP tools) as a `FunctionTool` from `agents.tool`. Each wrapper's `on_invoke_tool` calls back into xpander's tool execution path, so connector auth, observability, and retries still work. 4. **`xpander_agent.model_name`** is the model identifier configured on the agent (e.g. `gpt-4.1`, `gpt-4o`). Pass it to the OpenAI Agents SDK's `model` parameter. 5. **`Runner.run(native, input=task.to_message())`** drives the LLM loop. `task.to_message()` returns the task's user message (text plus any attachments) in the shape the runner expects. 6. **Writing back to `task.result`** lets xpander store the output and surface it in the API, Agent Studio, and any wired channels. ## 4. Edit the agent's system prompt `agent_instructions.json` contains the agent's system prompt and has exactly three fields: ```json agent_instructions.json theme={"dark"} { "role": [ "You are a customer support assistant for Acme.", "Always confirm the customer's account ID before taking any action." ], "goal": [ "Resolve the customer's issue in as few turns as possible.", "Escalate to a human if the request involves a refund over $500." ], "general": "Be concise, professional, and friendly. Never invent policy details; if you don't know something, say so and offer to escalate." } ``` Save the file and the next `xpander agent dev` syncs it to the control plane. ## 5. Wire knowledge-base retrieval (optional) The OpenAI Agents SDK doesn't auto-wire xpander's knowledge bases, so expose the retriever as a `@function_tool` the runner can call. The highlighted lines show the two integration points: building the retriever and concatenating it onto the auto-wired tool list. ```python xpander_handler.py highlight={7,14} theme={"dark"} from agents import Agent as OpenAIAgent, Runner, function_tool @function_tool async def search_knowledge_base(query: str, num_documents: int = 5) -> list[dict]: """Search the agent's linked knowledge bases. Returns top-k matching documents.""" # knowledge_bases_retriever() returns a callable: (query, agent=None, num_documents=5, **kwargs) retriever = xpander_agent.knowledge_bases_retriever() return retriever(query=query, num_documents=num_documents) native = OpenAIAgent( name=xpander_agent.name, instructions=xpander_agent.instructions.full, # Concatenate the auto-wired tools with the KB retriever. tools=[*xpander_agent.openai_agents_sdk_tools, search_knowledge_base], model=xpander_agent.model_name, ) ``` The retriever runs concurrent searches across every linked KB and returns the top N results by score. ## 6. Set up streaming (optional) For token-by-token output, decorate an `async def` that yields `TaskUpdateEvent` objects instead of returning a `Task`. The decorator detects the difference automatically. ```python streaming_handler.py highlight={17-29,31-38} theme={"dark"} from datetime import datetime, timezone from xpander_sdk import on_task, Task, Agents, TaskUpdateEvent, TaskUpdateEventType from agents import Agent as OpenAIAgent, Runner @on_task async def handler(task: Task): xpander_agent = await Agents(configuration=task.configuration).aget(agent_id=task.agent_id) native = OpenAIAgent( name=xpander_agent.name, instructions=xpander_agent.instructions.full, tools=xpander_agent.openai_agents_sdk_tools, model=xpander_agent.model_name, ) final_output = "" # Runner.run_streamed yields events as the LLM produces them. streaming = Runner.run_streamed(native, input=task.to_message()) async for event in streaming.stream_events(): # Surface each text delta to the platform's SSE stream. if event.type == "raw_response_event" and getattr(event.data, "delta", None): chunk = event.data.delta final_output += chunk yield TaskUpdateEvent( type=TaskUpdateEventType.Chunk, task_id=task.id, organization_id=task.organization_id, time=datetime.now(timezone.utc), data=chunk, ) task.result = final_output yield TaskUpdateEvent( type=TaskUpdateEventType.TaskFinished, task_id=task.id, organization_id=task.organization_id, time=datetime.now(timezone.utc), data=task, ) ``` Here's what's happening: 1. **`Runner.run_streamed(native, input=task.to_message())`** returns a `RunResultStreaming`. Iterating `streaming.stream_events()` yields raw response events, run-item events, and a final completion event. 2. **The `Chunk` event** forwards each text delta to the platform's SSE stream so clients render output as it arrives. 3. **The `TaskFinished` event** signals the end of the stream and carries the final task back to the platform. A streaming handler exposes itself only through `POST /invoke`, returning Server-Sent Events. The platform's SSE listener for cloud-deployed agents expects a regular handler that returns a `Task`. So if you need both an interactive streaming experience and platform-routed tasks, run two handlers, or have your streaming endpoint proxy through a regular handler. ## 7. Test local development Run the handler with the dev server. Tasks created from any channel (REST, Slack, Agent Studio) route to your laptop: ```bash theme={"dark"} # Starts the @on_task HTTP server and subscribes to the platform event stream. xpander agent dev ``` **Routing cloud traffic to a local instance is a preview feature.** When a local instance is running via `xpander agent dev`, it takes over and all tasks route to your locally running agent instead. Only one can be active at a time. For one-shot testing without a server: ```bash theme={"dark"} # Calls your handler exactly once with the given prompt and exits. python3 xpander_handler.py \ --invoke \ --prompt "Quick test" \ --output_format json \ --output_schema '{"answer":"string"}' ``` `--output_format` and `--output_schema` are useful for testing structured output without changing the agent's settings in the control plane. ## Troubleshooting The OpenAI Agents SDK instantiates its own OpenAI client and reads `OPENAI_API_KEY` from the environment. It does not pick up a custom LLM key configured on the agent in [Agent Studio](https://chat.xpander.ai). If the runner is using the wrong key, mirror the cloud-side custom key into your local `.env` as `OPENAI_API_KEY`. `Backend.aget_args()` currently dispatches only to the Agno builder. For every other framework, including the OpenAI Agents SDK, you load the Agent yourself with `Agents().aget(...)` and read the fields you need. There's no built-in session storage for the OpenAI Agents SDK. The runner exposes `result.to_input_list()`, which returns the full conversation as input items you can persist (Postgres, Redis, your own store) and pass back as `input=previous_items + new_message` on the next turn. If you'd rather not build that yourself, switch to the [Agno integration](/developers/frameworks/agno). Yes. `xpander_agent.openai_agents_sdk_tools` only supplies tools, not the runner's handoff configuration. You declare handoffs on the native `Agent` exactly as you would in any OpenAI Agents SDK app. Each agent in the handoff chain can independently load its own xpander tools. The OpenAI Agents SDK supports other model clients through its model-agnostic interface. `xpander_agent.model_name` is just a string. Pass it to whichever client you instantiate. The underlying model has to support tool calling for the integration to work end to end. ## Next steps The 10-minute scaffold-to-deploy walkthrough that produced the handler shown above. Wrap private APIs as tools with `@register_tool` and ship them through `openai_agents_sdk_tools`. What you'd gain by switching: session storage, knowledge-base auto-wiring, `Backend.aget_args()`. The SDK class names mapped onto agents, tasks, threads, and memory. What's auto-wired vs. manual for Agno, OpenAI Agents SDK, LangChain, and AWS Strands. # Introduction Source: https://docs.xpander.ai/developers/index Build AI Agents with the Python SDK, Xpander CLI, and your framework of choice The Python SDK is in **preview**. It's for building in-product agents — agents you write in Python and embed in your own product — and custom agents built on other frameworks (Agno, LangChain, OpenAI Agents, AWS Strands). To invoke or integrate xpander agents from an application, use the [REST API](/api-reference/invoke-api), which is stable and works from any language. Xpander.ai is the platform for building production AI agents that connect to enterprise APIs, data, and channels. There are two ways to start building AI agents: * **Agent Studio**: a visual app at [chat.xpander.ai](https://chat.xpander.ai) where you click together instructions, tools, and knowledge * **SDK + CLI**: the same platform, driven from Python The SDK lets you use different agent frameworks, create tools from private APIs, or embed Xpander in your Python tools. Anything you build in Agent Studio is also available in code. New to xpander overall? Start with [What is xpander.ai?](/overview/what-is-xpander). ## Install You need all three steps. The CLI and SDK are separate packages with different runtimes: the CLI ships via npm, the SDK via pip. ```bash theme={"dark"} # 1. CLI: creates agents, scaffolds projects, runs them locally npm install -g xpander-cli # 2. SDK: the runtime library you import in Python pip install "xpander-sdk[agno]" # 3. Auth: opens a browser, writes ~/.xpander/credentials xpander login ``` Python 3.12+ for the local dev server; the SDK itself works on 3.9+. 10-minute scaffold-to-running-agent walkthrough. Start here once you're installed. ## When to use code Agent Studio covers most agent-building. Reach for the SDK when one of these applies: * **Use a specific framework.** You're already invested in [Agno](/developers/frameworks/agno), [OpenAI Agents SDK](/developers/frameworks/openai-agents), [LangChain](/developers/frameworks/langchain), or [AWS Strands](/developers/frameworks/aws-strands). * **Wrap a private API as a tool.** Decorate a Python function with [`@register_tool`](/developers/tools/custom-tools); the SDK generates the JSON schema from your type hints. Example: a `lookup_customer(id)` tool that hits your internal billing service. * **Embed in an existing service.** Run an agent inside code you already deploy (a FastAPI worker, a cron job, a Slack bot) without standing up a separate process. * **Programmatic scale.** Spawn many tasks at once. Example: backfill structured fields across 10k support tickets, or run an eval suite that compares two agent versions on a fixed prompt set. If none of that applies, Agent Studio is faster. ## How it fits together Xpander splits into two halves: 1. The **control plane** (cloud or self-hosted) owns the agent's identity: instructions, tools, model + credentials, knowledge bases, session storage. 2. **Your process** owns the execution loop: the framework that decides what to call and when. They talk through `Backend`, which fetches the agent and returns a dict ready to splat into your framework's `Agent` constructor. ``` ┌─────────────────────────┐ ┌─────────────────────────────┐ │ xpander control plane │ │ Your process │ │ (cloud or self-hosted) │ │ │ │ │ │ Backend.aget_args(...) │ │ • Agent definition │ ──────▶ │ returns framework args │ │ • Tools / connectors │ │ │ │ • Knowledge bases │ │ AgnoAgent(**args) │ │ • Model + credentials │ │ runs the LLM loop │ │ • Instructions │ │ │ │ • Postgres (sessions) │ ◀────── │ @on_task receives a Task, │ └─────────────────────────┘ │ writes task.result, returns │ └─────────────────────────────┘ ``` This split is why the SDK stays small and your code stays your code. There's no xpander-flavored wrapper around your framework. You instantiate the framework's own `Agent` class with arguments xpander provides. ## What you'll work with A typical project pulls in three pieces: * **Python SDK** (`xpander-sdk`): runtime classes (`Backend`, `Agents`, `Task`) and decorators (`@on_task`, `@register_tool`). The class-by-class breakdown lives in [Core Concepts](/developers/core-concepts). * **CLI** (`xpander`): scaffolds projects, runs agents locally, manages auth. Every command is in the [CLI Reference](/developers/cli-reference/overview). * **A framework**: [Agno](/developers/frameworks/agno) is the recommended path because the SDK does the most wiring for it. [OpenAI Agents SDK](/developers/frameworks/openai-agents), [LangChain](/developers/frameworks/langchain), and [AWS Strands](/developers/frameworks/aws-strands) are also supported; the [Frameworks overview](/developers/frameworks) compares what's auto-wired vs. manual for each. When you run `xpander agent new`, the CLI generates a starter project in your current directory. Here's what it creates: ``` xpander_handler.py # Your @on_task handler. The entry point. xpander_config.json # Agent ID, framework selection. agent_instructions.json requirements.txt .env # XPANDER_API_KEY, XPANDER_ORGANIZATION_ID, XPANDER_AGENT_ID. ``` For most projects, `xpander_handler.py` is the only file you'll edit. ## What to read next Scaffold and run your first agent locally in under 10 minutes. The SDK class names mapped onto agents, tasks, threads, tools, and memory. Pick a framework and see what xpander wires up for you. Per-module class and method documentation. # Document Management Source: https://docs.xpander.ai/developers/knowledge/document-management Add, list, and remove documents in a knowledge base programmatically A knowledge base is a document collection an agent can query as part of its reasoning. The Workbench has a drag-and-drop UI for managing documents, but for anything programmatic (syncing from a CMS, batch-uploading from S3, refreshing a doc set on a schedule) you'll want the SDK. Knowledge base retrieval is wired in automatically only for **Agno**. For LangChain, OpenAI Agents SDK, and AWS Strands, you need to add the retriever as a tool manually. See the [framework pages](/developers/frameworks/agno) for details. ## Prerequisites * **Complete the [Quickstart](/developers/quickstart)** so the CLI, SDK, and `xpander login` are already set up. * **Python 3.12+** for the local handler. ## 1. List your knowledge bases Knowledge bases live at the organization level, not on a specific agent. You attach one or more KBs to an agent in the Workbench, and the agent's framework gets a retriever wired in automatically. ```python theme={"dark"} from xpander_sdk import KnowledgeBases kbs = KnowledgeBases() for kb in kbs.list(): print(kb.name, kb.id, kb.total_documents) ``` Each `KnowledgeBase` object has these fields: | Field | Type | What it's for | | ----------------- | ----- | ---------------------------------------------------------------------------------------------------------- | | `id` | `str` | Stable identifier. Use this to attach the KB to an agent or look it up later. | | `name` | `str` | Human-readable label. | | `description` | `str` | Shown to the agent as context for when to query this KB. | | `type` | `str` | `managed` (xpander handles embeddings and storage) or `external` (your own vector store, enterprise-only). | | `total_documents` | `int` | Count of documents currently indexed. | ## 2. Create a KB ```python theme={"dark"} kb = kbs.create( name="Engineering Runbooks", description="Internal incident response and on-call documentation", ) ``` Some notes: * Knowledge bases are xpander-managed, which means chunking, embedding, vector storage, and search are configured automatically. * The agent reads `description` to decide when to query this knowledge base. To bring your own self-managed knowledge base, [contact sales](https://cal.com/team/xpander-ai/activate). ## 3. Add documents Documents are referenced by URL, not uploaded as bytes. The KB fetches each URL, parses it, chunks it, embeds the chunks, and stores them. ```python theme={"dark"} docs = kb.add_documents( document_urls=[ "https://internal.acme.com/runbooks/payment-failures.pdf", "https://internal.acme.com/runbooks/database-restore.md", ], sync=True, ) for d in docs: print(d.id, d.document_url) ``` Some notes: * **`sync=True` waits for processing before returning.** Use it when you need to search the documents in the same script that uploads them. Use `sync=False` (the default) for batch jobs where you don't need to block on completion. * **URLs must be reachable from xpander's infrastructure.** For internal documents not on the public web, host them somewhere xpander can reach: S3 with a presigned URL, an internal HTTPS endpoint with IP whitelisting, or a public bucket. There's no in-memory-blob entry point; if a document only exists in memory (a generated report, a transient export), upload it to storage first. * **Documents behind auth need a credentialless URL.** The platform's fetcher can't carry your session. Use S3 presigned URLs that include a short-lived token, or make a temporary public link. Supported formats: PDF, Markdown, plain text, HTML, CSV, JSON, and common Office formats. ## 4. List documents in a KB ```python theme={"dark"} documents = kb.list_documents() for d in documents: print(d.id, d.document_url, d.status) ``` `status` is most useful when you've added documents asynchronously and want to know which ones finished processing. Failed documents stay in the list with their error captured, so you can find and re-add the URLs after fixing whatever was wrong. ## 5. Remove documents ```python theme={"dark"} to_remove = [d.id for d in documents if "deprecated" in d.document_url] kb.delete_multiple_documents(document_ids=to_remove) ``` Deletes are immediate and final. Re-adding a URL re-processes the file from scratch with a new document ID. ## 6. Delete a KB ```python theme={"dark"} kb.delete() ``` This wipes the KB and every document in it. There's no soft-delete or retention window. Detach it from any agents that reference it before calling this. Otherwise those agents will be referencing a KB that no longer exists. ## 7. Attach a KB to an agent ```python highlight={5} theme={"dark"} from xpander_sdk import Agents agent = Agents().get(agent_id="agt_01H...") agent.attach_knowledge_base(knowledge_base_id=kb.id) ``` Once attached to an agent, the knowledge base is available in all future sessions. ## Sync patterns Two patterns come up repeatedly in production: **Keeping a KB in sync with a source-of-truth elsewhere.** Run a scheduled job that fetches the latest URL list from your CMS, diffs it against `kb.list_documents()`, removes documents no longer in the source, and adds new ones. With `sync=True` on the add, the job is idempotent. **Per-tenant KBs in a multi-tenant system.** One KB per customer, attached to a customer-specific agent. The setup overhead is one `kbs.create(name=...)` call when you onboard a customer, plus an `agent.attach_knowledge_base(...)` call to link it. ## Troubleshooting The most common causes are: the URL isn't reachable from xpander's infrastructure (private network, missing auth), the file format isn't supported, or the file is malformed. Check the `status` field on the document object; it carries the error message. Fix the URL or file and re-add. Large PDFs and Office documents can take a while to chunk and embed. Switch to `sync=False` and poll `kb.list_documents()` until the document's `status` is `ready`. Or break the upload into smaller batches. Check that the KB is attached to the agent (visible in the Workbench under the agent's KB tab) and that the agent has been published after attachment. For frameworks other than Agno, you may need to wire the retriever in manually. See the [framework pages](/developers/frameworks/agno). Detach the KB from all agents before deleting it. In the Workbench, open each agent's KB tab and remove the reference. Then delete the KB. An agent referencing a deleted KB will silently get no results from KB queries. ## Next steps Query a KB directly from code, outside the agent's reasoning loop. How attached KBs reach the agent's reasoning loop. Full method-level docs. Trim large KB responses before they reach the LLM. # Semantic Search Source: https://docs.xpander.ai/developers/knowledge/semantic-search Query a knowledge base from code When a knowledge base is attached to an agent, the framework calls it automatically as part of the agent's reasoning loop and you don't see the search call. Sometimes you want to search directly: building a search box, enriching a record before it goes into a workflow, or testing how a query ranks against your corpus. That's what `kb.search` and `agent.knowledge_bases_retriever()` are for. Knowledge base retrieval is wired in automatically only for **Agno**. For LangChain, OpenAI Agents SDK, and AWS Strands, you need to add the retriever as a tool manually. See the [framework pages](/developers/frameworks/agno) for details. ## Prerequisites * **Complete the [Quickstart](/developers/quickstart)** so the CLI, SDK, and `xpander login` are already set up. * **At least one knowledge base** created and populated via the Workbench or the [Document Management SDK](/developers/knowledge/document-management). ## 1. Search a knowledge base ```python theme={"dark"} from xpander_sdk import KnowledgeBases kb = KnowledgeBases().get(knowledge_base_id="kb_01H...") results = kb.search( search_query="how do we handle refund requests over $500?", ) for r in results: print(f"score={r.score:.3f} source={r.document_name}") print(r.content[:200]) ``` Each result object has these fields: | Field | What it's for | | --------------- | ------------------------------------------------- | | `content` | The matched chunk of text, not the full document. | | `score` | Relevance score, higher is better. | | `document_name` | Name of the source document. | | `document_id` | Stable ID of the source document. | Results are ordered by score descending. ## 2. Tune the query Two parameters you control: * **`top_k`** controls how many results are returned. It defaults to 10. Lower it for tightly scoped queries where you only want the best match; raise it when feeding results into a downstream LLM that can re-rank or summarize. * `use_bubble` enables **bubble search** which returns the matched chunk *plus surrounding context* rather than the chunk in isolation. Use it when chunks are small (e.g., per-paragraph) and the agent needs surrounding text to make sense of a match. Skip it when chunks are already large enough to be self-contained. ```python highlight={3-5} theme={"dark"} results = kb.search( search_query="incident escalation policy", top_k=3, use_bubble=True, bubble_size=2000, # character window around each match, default 1000 ) ``` ## 3. Search across multiple KBs from an agent If your agent has more than one knowledge base attached, `agent.knowledge_bases_retriever()` returns a callable that searches all of them and merges results by score: ```python highlight={3-4} theme={"dark"} from xpander_sdk import Agents agent = Agents().get(agent_id="agt_01H...") search = agent.knowledge_bases_retriever() results = search(query="quarterly metrics", num_documents=10) for r in results: print(r["score"], r["document_name"], r["content"][:100]) ``` Use this when you want the agent's knowledge base context without its reasoning loop. `num_documents` controls the merged result count. It's the equivalent of `top_k` across the combined corpus. ## Troubleshooting Check that the KB has documents with `status=ready` (see [Document Management](/developers/knowledge/document-management)). A KB with all documents still processing or failed will return empty results. Also confirm the query isn't empty and `top_k` is greater than 0. Low scores usually mean the query language doesn't match the document language, or the content is too sparse. Try rephrasing the query to match how the documents describe the topic. If the corpus is large and diverse, raising `top_k` and letting a downstream LLM re-rank often helps more than query reformulation. No KBs are attached to the agent. Attach at least one via the Workbench (agent's KB tab) or via `agent.attach_knowledge_base(knowledge_base_id=...)` in code. Then reload the agent before calling the retriever. For frameworks other than Agno, the retriever isn't wired in automatically; you need to add it as a tool explicitly. See the [framework pages](/developers/frameworks/agno) for the per-framework setup. Also check that the agent is published after attaching the KB. ## Next steps Add, list, and remove documents from a KB programmatically. How attached KBs reach the agent's reasoning loop in each framework. Trim large KB responses before they reach the LLM. Full method-level docs. # Agent Memories Source: https://docs.xpander.ai/developers/memory/agent-memories Organization-wide knowledge the agent always carries Agent memories are facts the agent should know in every conversation, regardless of who is talking to it. Use them for things that should be true everywhere your agent runs: "Our refund policy is 30 days." "We use JIRA for bug tracking, Linear for product." "All deploys ship on Tuesdays and Thursdays." Unlike user memories, agent memories are scoped only to `agent_id`. Any memory created here becomes part of every conversation for every user. ```mermaid theme={"dark"} graph LR Alice --- S1["Session 1"] Alice --- S2["Session 2"] Bob --- S3["Session 3"] S1 --- Agent["Support Bot"] S2 --- Agent S3 --- Agent Agent --- GM[("Agent Memory")] ``` Agent memories are wired in automatically only for **Agno**. The DB connection and helpers on this page raise `NotImplementedError` on LangChain, OpenAI Agents SDK, and AWS Strands. See the [framework pages](/developers/frameworks/agno) for the manual integration story. ## When to use agent memories Pick the right layer for the fact: | The fact applies to... | Use | | --------------------------------- | ------------------------------------------------------- | | One specific user | [User memory](/developers/memory/user-memories) | | A single conversation | [Session storage](/developers/memory/session-storage) | | Every conversation this agent has | **Agent memory** | | A queryable document corpus | [Knowledge base](/developers/knowledge/semantic-search) | A useful test: if the fact is short (one or two sentences) and would matter on every turn, it's an agent memory. If it's a multi-page document the agent might need sometimes, it belongs in a knowledge base. **Agent memories vs. system prompt instructions:** instructions are part of the agent's identity and require an Agent Studio change to update. Agent memories are mutable from code, so an automation can update them when the underlying fact changes. "Refund window is 14 days" is policy that might shift quarterly; encoding it as a memory means a single SDK call keeps the agent current, no UI round-trip needed. In agentic mode the agent can also extract and add memories itself, which instructions can't do. ## Configuration Settings live on `agent.agno_settings` and are toggled in the agent's Memory tab in [Agent Studio](https://chat.xpander.ai). Agent memories are single-agent only; the wiring is skipped on Teams. UI walkthrough for toggling agent memory and switching between agentic and manual modes. | Setting | What it controls | Default | | ----------------- | ----------------------------------------------------------------------------------------------------------------------- | ------- | | `agent_memories` | Turn cultural-knowledge storage on. The agent reads entries into the system prompt every turn. | `False` | | `agentic_culture` | When on, the agent identifies and stores org-level facts as it learns them. When off, your code writes through the SDK. | `False` | Read which mode is active off the loaded agent: ```python theme={"dark"} xpander_agent = await Agents().aget(agent_id="agt_01H...") print(xpander_agent.agno_settings.agent_memories) print(xpander_agent.agno_settings.agentic_culture) ``` **Manual vs agentic mode, pick one:** * **Manual mode** (`agent_memories = True`): you write the memories. The agent reads them during reasoning. Good for facts you want strict control over: compliance text, policy wording. * **Agentic mode** (`agentic_culture = True`): the agent identifies and stores org-level facts as it learns them through conversations. Good when you want the agent to build up its own picture of how your org operates. Both inject memories into the agent's system prompt at the start of every turn with no retrieval step needed. The two modes are mutually exclusive. ## Add a memory To add an Agent Memory, you need: * a `name` identifying the memory * `content` that carries the main body text ```python highlight={5,7-12} theme={"dark"} from agno.db.schemas.culture import CulturalKnowledge from xpander_sdk import Agents agent = await Agents().aget(agent_id="agt_01H...") db = await agent.aget_db(async_db=True) await db.upsert_cultural_knowledge( CulturalKnowledge( name="refund-policy", content="Refund policy: full refund within 30 days, partial after.", ) ) ``` You can also specify some optional parameters: | Field | Type | What it's for | | ------------ | ----------- | -------------------------------------------------------------------------------------------------------------------------------------------------------- | | `summary` | `str` | A condensed version of `content`. Shown in previews; useful for long entries where you want a shorter form in logs or admin UIs. | | `categories` | `list[str]` | Tags for grouping or filtering entries (`["policy"]`, `["engineering", "ops"]`). | | `notes` | `list[str]` | Free-form annotations (caveats, sources, change history). Not injected into the agent's context directly. | | `input` | `str` | The original text or conversation turn that produced this memory, when set by agentic mode. Useful for auditing what prompted the agent to store a fact. | | `metadata` | `dict` | Arbitrary key-value pairs for your own tooling (timestamps, author, source system, etc.). Not read by the agent. | `agent_id` and `team_id` are set automatically by the SDK from the loaded agent. Don't set them manually. ## Inspect memories ```python highlight={1} theme={"dark"} memories = await db.get_all_cultural_knowledge() for m in memories: print(m.id, m.name, m.content) ``` Use this to audit what agentic mode has accumulated, build an admin view, or verify that a seed run actually wrote. Filter by `name` or `limit` if the store has grown large. ## Edit or delete To edit, upsert with an existing `id`: ```python highlight={3,5} theme={"dark"} await db.upsert_cultural_knowledge( CulturalKnowledge( id="cul_existing_id", name="refund-policy", content="Refund policy: full refund within 14 days, partial after.", ) ) ``` To remove one record: ```python theme={"dark"} await db.delete_cultural_knowledge(id="cul_existing_id") ``` To wipe every entry on the agent (destructive, no confirmation): ```python theme={"dark"} await db.clear_cultural_knowledge() ``` ## Token cost Agent memories live in the system prompt, which means they are injected in the prompt sent to the LLMs in every turn. This increases cost and latency. Keep entries short and high-signal. Prune periodically. If the store has grown past the point where every entry is genuinely useful on every turn, move the excess to a [knowledge base](/developers/knowledge/semantic-search) where it's retrieved on demand rather than always injected. ## Troubleshooting Confirm `agent_memories=True` (or `agentic_culture=True`) is set via `xpander_agent.agno_settings`, then reload the agent so the next task picks up the new memory. Cached `Agent` instances from before the insert won't reflect it until `Agents().aget(...)` runs again. List with `db.get_all_cultural_knowledge()`, find the row, and call `db.delete_cultural_knowledge(id=...)`. Since agent memories are global, a single bad row affects every user; fix it quickly. For ongoing protection, switch from `agentic_culture` to `agent_memories` (manual mode) so the agent can no longer write on its own. In `agentic_culture` mode the agent will rewrite memories it considers important. If a deleted memory keeps reappearing, switch to manual mode (`agent_memories=True`) so the agent stops writing entirely, or rephrase the underlying fact so the agent doesn't infer the same thing again. Too many agent memories. Prune aggressively or move long-form content to a [knowledge base](/developers/knowledge/semantic-search) where it's retrieved on demand. A useful rule: anything you wouldn't want to read on every turn shouldn't live in agent memories. Agent memories are single-agent only; the cultural-knowledge wiring is skipped on Teams by design. If you have a multi-agent setup and need shared organizational facts, attach them to each member agent individually, or move the content into a knowledge base the team shares. ## Next steps Per-user facts, the layer below. Single-conversation memory. For larger bodies of knowledge the agent retrieves on demand. The full args-dict reference, including `add_culture_to_context` and the agentic-culture wiring. # Session Storage Source: https://docs.xpander.ai/developers/memory/session-storage Conversation history within a thread, backed by Postgres Session storage is the simplest of the three memory layers: the agent remembers what was said earlier in the same conversation thread. It's on by default for Agno-backed agents and lives in a per-agent Postgres schema xpander manages for you. Every thread has its own history. As long as messages share a `session_id`, the agent sees the full history up to the configured limit. Start a new thread and the slate is clean. Multiple users can share a thread and they see the same conversation, but it's still self-contained. ```mermaid theme={"dark"} graph LR Alice Bob subgraph SG1[" "] direction TB S1["Session 1"] DB1[("Session Storage")] S1 --- DB1 end subgraph SG2[" "] direction TB S2["Session 2"] DB2[("Session Storage")] S2 --- DB2 end subgraph SG3[" "] direction TB S3["Session 3"] DB3[("Session Storage")] S3 --- DB3 end Agent["Support Bot"] Alice --- S1 Alice --- S2 Bob --- S1 Bob --- S3 S1 ------ Agent S2 ------ Agent S3 ------ Agent style SG1 fill:none,stroke:none style SG2 fill:none,stroke:none style SG3 fill:none,stroke:none ``` Session storage is wired in automatically only for **Agno**. The SDK helpers on this page raise `NotImplementedError` on LangChain, OpenAI Agents SDK, and AWS Strands. For those frameworks, manage session continuity through the framework's own state primitives. See the [framework pages](/developers/frameworks/agno) for details. ## Configuration The settings below live on `agent.agno_settings` and are toggled in the agent's Memory tab in [Agent Studio](https://chat.xpander.ai). UI walkthrough for toggling session storage and tuning history depth. Read them back from the loaded agent to confirm what's live: ```python theme={"dark"} from xpander_sdk import Agents xpander_agent = await Agents().aget(agent_id="agt_01H...") print(xpander_agent.agno_settings.session_storage) print(xpander_agent.agno_settings.num_history_runs) ``` | Setting | What it controls | Default | | ----------------------------- | -------------------------------------------------------------------------------------------------------------------- | ------- | | `session_storage` | Whether the framework writes turn-by-turn history to Postgres. | `True` | | `num_history_runs` | How many prior runs to load into context at the start of each turn. One run = one user message + one agent response. | `10` | | `max_tool_calls_from_history` | Cap on tool calls replayed from history. `0` means no cap. | `0` | | `session_summaries` | Generate a summary of each completed session for monitoring views. Doesn't affect context. | `False` | `num_history_runs` is the big knob. Tune it down to `3` or `5` for high-volume tool agents, up to `20` or more for long analytical conversations. Higher numbers mean longer memory but more tokens per turn. ### When to turn it off The default is on because most agents benefit from it. Reasons to flip `session_storage` off: * One-shot tools that don't have conversational threads (a webhook handler that returns a single result, a scheduled enrichment job). * Performance-sensitive paths where the per-turn DB read is meaningful overhead. * Agents handling regulated data where you don't want any conversation persistence at all. The framework skips the DB wiring on the next agent load. ## Inspect sessions from code The session helpers are on the loaded agent. They let you: * List every session by `user_id` * Get full message history for every session * Delete a session and its message history ```python highlight={6,11,15} theme={"dark"} from xpander_sdk import Agents agent = await Agents().aget(agent_id="agt_01H...") # Every session a given user has had with this agent. sessions = await agent.aget_user_sessions(user_id="user@example.com") for s in sessions: print(s.session_id, len(s.messages)) # A specific session by ID. session = await agent.aget_session(session_id="sess_abc") print(session.messages) # Wipe one. await agent.adelete_session(session_id="sess_abc") ``` If you'd rather reach into Postgres directly (custom queries, an admin UI of your own), `agent.aget_db()` returns the same connection the framework reads and writes through: ```python theme={"dark"} db = await agent.aget_db(async_db=True) # agno.db.postgres.AsyncPostgresDb, scoped to this agent's schema. ``` Most session work goes through the agent methods above; reach for the DB only when those don't expose what you need. ## Troubleshooting By default, every REST invocation gets a fresh `session_id`. To get continuity across calls, pass the same `session_id` (or the same task's parent ID) on each request. The chat panel and Slack integration manage this for you; programmatic clients have to do it explicitly. No. Each agent has its own Postgres schema, so sessions are scoped to one agent. If you need agent A to see what agent B did, use the [agent-to-agent (A2A) pattern](/developers/deployment/invocation-channels#agent-to-agent-a2a): one agent invokes the other and gets the result back as a tool response. Iterate `agent.aget_user_sessions(user_id)` for the affected user, filter by date, and call `agent.adelete_session(session_id)` per match. Schedule the job through any cron mechanism in your infrastructure; xpander doesn't run retention policies on your behalf. Session storage is on by default, so the agent's wiring expects a reachable Postgres. For cloud-hosted agents this is automatic. For self-hosted or air-gapped deployments, check the connection string with `await agent.aget_connection_string()` and confirm the host is reachable, or toggle `session_storage` off in [Agent Studio](https://chat.xpander.ai). ## What to read next Facts about a specific user that persist across all their sessions. Org-wide knowledge the agent always carries. The full args-dict reference, including every session-storage field `aget_args` wires up. Trim chatty connector responses before they reach the LLM and bloat session history. # User Memories Source: https://docs.xpander.ai/developers/memory/user-memories Per-user facts that persist across sessions User memories are the layer above session storage. While session storage keeps a single conversation coherent, user memories let the agent remember things about a specific person across every conversation they have. "Prefers concise answers." "This user is on the enterprise tier." "Their renewal is in November." The data lives in the same Postgres schema as session storage, scoped by `user_id` instead of `session_id`. Each user's memories are completely isolated. One user's preferences never leak into another's conversations, even when they interact with the same agent. The two layers turn on independently, so you can have user memories without session storage (or vice versa). ```mermaid theme={"dark"} graph LR AM[("Alice's User Memory")] --- Alice BM[("Bob's User Memory")] --- Bob Alice --- S1["Session 1"] Alice --- S2["Session 2"] Bob --- S3["Session 3"] S1 --- Agent["Support Bot"] S2 --- Agent S3 --- Agent ``` User memories are wired in automatically only for **Agno**. The DB connection and helpers on this page raise `NotImplementedError` on LangChain, OpenAI Agents SDK, and AWS Strands. See the [framework pages](/developers/frameworks/agno) for the manual integration story. ## Configuration The settings below live on `agent.agno_settings` and are toggled in the agent's Memory tab in [Agent Studio](https://chat.xpander.ai). Both modes require session storage to be on, since user memories are stored alongside sessions. UI walkthrough for toggling user memory and switching between agentic and manual modes. | Setting | What it controls | Default | | ---------------- | ------------------------------------------------------------------------------------- | ------- | | `user_memories` | Turn user-memory storage on. The agent reads memories during reasoning. | `False` | | `agentic_memory` | When on, the agent decides what to write. When off, your code writes through the SDK. | `False` | Read which mode is active off the loaded agent: ```python theme={"dark"} xpander_agent = await Agents().aget(agent_id="agt_01H...") print(xpander_agent.agno_settings.user_memories) print(xpander_agent.agno_settings.agentic_memory) ``` ### Manual vs agentic mode There are two flavors, and they're mutually exclusive: * **Manual mode** (`user_memories = True`): the agent has access to a memory store, but it doesn't decide on its own when to write to it. Your code calls the memory APIs to add, update, and remove facts. * **Agentic mode** (`agentic_memory = True`): the agent decides when to write memories. As conversations happen, it surfaces facts worth remembering and stores them automatically. Pick one based on how much control you want. Agentic mode is closer to "talking to a human who pays attention"; manual mode is closer to "writing to a database the agent can read." Most product use cases benefit from agentic mode (the user gets the magical "it remembered" experience without you doing anything). Cases where you want strict control over what's stored (regulated data, customer-specific compliance rules) benefit from manual mode. ## Identifying the user The agent identifies a user via the `User` object on the task input. When you create a task, pass the user details: ```python highlight={3,5-9} theme={"dark"} from xpander_sdk import User task = await agent.acreate_task( prompt="Remind me what we discussed last week about the budget review.", user_details=User( id="user-001", email="user@example.com", first_name="Example", ), ) ``` Here's what's happening: 1. **`email` is the only required field** on `User`. `id`, `first_name`, `last_name`, `additional_attributes`, and `timezone` are optional. 2. **The framework scopes the memory lookup** by these fields together, so anything stored against that user surfaces the next time they show up. 3. **Inside `@on_task`, the same object lives on `task.input.user`**: read it back when you need the active user. If you don't pass user details on task creation, user memories are effectively off for that task: the agent has nowhere to scope the lookup. Make sure your invocation path threads a stable user identifier through every entry point (REST API, Slack, chat widget). ## Add, inspect, and edit memories On Agno-backed agents memories are loaded into context automatically whenever `user_memories` or `agentic_memory` is on. You don't have to do anything for the agent to see them. Reach for the DB when you want to add memories yourself (manual mode), audit what's been stored, correct something the agent kept by mistake, or seed facts from another system. `agent.aget_db()` returns the same `AsyncPostgresDb` connection the framework reads and writes through, so admin tools, migration scripts, and your handler all share one source of truth. ### Add a memory `db.upsert_user_memory` inserts a new memory or updates an existing one by `memory_id`. In manual mode this is how your app writes memories; in agentic mode use it to seed or override what the agent stored on its own. ```python highlight={1,5,8-10} theme={"dark"} from agno.db.schemas.memory import UserMemory from xpander_sdk import Agents agent = await Agents().aget(agent_id="agt_01H...") db = await agent.aget_db(async_db=True) await db.upsert_user_memory( UserMemory( user_id="user@example.com", memory="Prefers concise answers, no preamble.", ) ) ``` Here's what's happening: 1. **`UserMemory.memory` carries the content** (not `content`). `user_id`, `topics`, `input`, and `feedback` are the other useful fields. 2. **`memory_id` is auto-generated on insert.** Pass an existing `memory_id` to update that record in place. 3. **The upsert is keyed by `memory_id`**, so the same call shape adds *or* edits depending on whether the ID exists. A common pattern: when the user takes an action in your app that implies a preference (toggling a setting, completing onboarding with specific choices), upsert it as a memory so the agent picks it up the next time it talks to them. To seed memories from an external source (CRM, product DB) on first contact, wrap the upsert calls in an `@on_boot` hook or run them in the handler when `get_user_memories` returns empty. ### Inspect memories `db.get_user_memories(user_id=...)` lists every memory keyed to one user. Each `UserMemory` exposes `memory_id`, `memory`, `topics`, `created_at`, and `updated_at`. ```python highlight={1,3} theme={"dark"} memories = await db.get_user_memories(user_id="user@example.com") for m in memories: print(m.memory_id, m.memory, m.created_at) ``` Use this to audit what agentic mode has accumulated, build a "your saved facts" view for the user, or check that a seed run actually wrote. ### Edit or delete To edit, upsert with an existing `memory_id`: ```python highlight={3,5-7} theme={"dark"} await db.upsert_user_memory( UserMemory( memory_id="mem_existing_id", user_id="user@example.com", memory="Prefers concise answers, no preamble. Avoid pleasantries.", ) ) ``` To remove one record: ```python theme={"dark"} await db.delete_user_memory(memory_id="mem_existing_id") ``` For bulk removal (a "forget me" request, a compliance purge): ```python theme={"dark"} await db.delete_user_memories( memory_ids=["mem_1", "mem_2"], user_id="user@example.com", ) ``` ### SDK reference | Method | Returns | What it's for | | ---------------------------------------------- | ------------------ | ------------------------------------------------------------------------------- | | `agent.aget_db(async_db=True)` | `AsyncPostgresDb` | The Postgres handle scoped to this agent's schema. Sync form: `agent.get_db()`. | | `db.get_user_memories(user_id)` | `list[UserMemory]` | List every memory keyed to one user. | | `db.upsert_user_memory(UserMemory(...))` | `UserMemory` | Insert or update a memory by `memory_id`. | | `db.delete_user_memory(memory_id)` | `None` | Remove one record by ID. | | `db.delete_user_memories(memory_ids, user_id)` | `None` | Bulk delete. | The exact API surface is Agno's; consult the [Agno docs](https://docs.agno.com) for the full method list. ## Token cost considerations User memories cost LLM calls. In agentic mode the agent decides when to extract memories from a conversation (one extra LLM call per session, sometimes more). On every turn, the relevant memories are loaded into context, which costs tokens. For high-volume agents, the math matters: if your agent handles 100,000 conversations a month and each one triggers a memory-extraction call, that's 100,000 extra LLM calls. For most production cases the trade is worth it, but verify against your usage patterns. ## Troubleshooting First check that you're passing `user_details` (or `task.input.user`) on every invocation. Without an identifier, memories have nowhere to scope. Then confirm `user_memories` or `agentic_memory` is on via `xpander_agent.agno_settings`. If the user is brand new and the agent is in agentic mode, give it a few exchanges to find something worth remembering. The agent only writes when it decides a fact is worth remembering. Brief, transactional conversations may produce nothing. Verify `agentic_memory=True` (not `user_memories=True`; they're mutually exclusive) and that the conversation has at least a few exchanges with substantive content. Look it up with `db.get_user_memories(user_id=...)`, find the offending row, and call `db.delete_user_memory(memory_id=...)`. For systematic prevention, switch from agentic to manual mode so the agent can no longer write on its own. Confirm the `UserMemory.user_id` matches the `User.email` (or `User.id` if you're using IDs consistently) that the agent will see at runtime. Mismatched scoping is the most common cause. Then verify the agent is loaded fresh after the write; cached `Agent` instances from before the insert won't reflect it until the next `Agents().aget(...)`. Memories all load into context. Prune aggressively: iterate `get_user_memories`, drop stale rows with `delete_user_memory` or `delete_user_memories`, and consider moving long-form context to a [knowledge base](/developers/knowledge/semantic-search) where it's retrieved on demand instead of always-on. ## What to read next Org-wide knowledge, the layer above user memories. Single-conversation memory, the layer below. The full args-dict reference for what `aget_args` wires up. Trim chatty connector responses before they reach the LLM. # Quickstart Source: https://docs.xpander.ai/developers/quickstart Create an agent and run it locally. Entirely from the terminal. About 10 minutes. This page builds an agent end-to-end from the command line. No Agent Studio, no clicking. By the end, you'll have: 1. Created the agent in xpander's control plane. 2. Run its handler locally against real prompts. If you'd rather start with a visual builder, the [Platform Guides Quickstart](/guides/quickstart) walks through the same flow inside [Agent Studio](https://chat.xpander.ai). ## Prerequisites * **Node.js 20+** for the CLI. * **Python 3.12+** for the local dev server. * **An LLM provider key in your shell** (`OPENAI_API_KEY`, `ANTHROPIC_API_KEY`, or whichever provider you'll use). The agent runs against this key locally; in production, you can override it from the agent config. ## 1. Install and authenticate All three commands are required: 1. The CLI ships via npm. 2. The SDK ships via pip. 3. `login` writes credentials that both the CLI and the SDK read. ```bash theme={"dark"} # 1. CLI: creates agents, scaffolds projects, runs them locally npm install -g xpander-cli # 2. SDK: the runtime library you import in Python pip install "xpander-sdk[agno]" # 3. Auth: opens a browser, writes ~/.xpander/credentials xpander login # Optional: on CI or a machine without a browser, use this instead. # Paste an API key from https://platform.xpander.ai/settings. xpander configure ``` ## 2. Create the agent `xpander agent new` does two things at once: 1. It creates the agent in xpander's control plane (giving it an ID, a default model, and an empty tool list). 2. It scaffolds the project files into the folder you point at. ```bash theme={"dark"} # Create an agent named "my-first-agent" using the Agno framework # and scaffold its files into the current directory. xpander agent new \ --name "my-first-agent" \ --framework "agno" \ --folder "." ``` Drop the flags to use the interactive wizard, which asks for the same three values one at a time. When the command finishes, the current directory contains: ``` xpander_handler.py # Your @on_task entry point. xpander_config.json # Agent ID, framework selection, runtime settings. agent_instructions.json # Agent system prompt (edit this to change behavior). requirements.txt # Python dependencies. .env # Prefilled with API key, org ID, and the new agent's ID. ``` Set up a virtual environment and install the dependencies: ```bash theme={"dark"} # Use python3 explicitly so macOS doesn't fall back to system Python 2 python3 -m venv .venv source .venv/bin/activate pip install -r requirements.txt ``` ## 3. Read the handler The scaffolded `xpander_handler.py` is the canonical pattern for an xpander agent. Every example in the rest of these docs is a variation on this: ```python xpander_handler.py theme={"dark"} from dotenv import load_dotenv load_dotenv() from xpander_sdk import on_task, Task, Backend, Tokens from agno.agent import Agent @on_task async def handler(task: Task) -> Task: # 1. Fetch the agent's full configuration from xpander's control plane backend = Backend(configuration=task.configuration) agno_args = await backend.aget_args(task=task) # 2. Build the framework's own Agent class with that config agno_agent = Agent(**agno_args, debug_mode=True) # 3. Run the LLM loop with the task's input, files, and images result = await agno_agent.arun( input=task.to_message(), files=task.get_files(), images=task.get_images(), ) # 4. Write the result back so xpander can store and display it task.result = result.content task.tokens = Tokens( prompt_tokens=result.metrics.input_tokens, completion_tokens=result.metrics.output_tokens, ) task.used_tools = [t.tool_name for t in (result.tools or [])] return task ``` Here's what's happening: 1. `Backend(...).aget_args(task=task)` calls the xpander control plane and returns a dict containing the full agent configuration: instructions, tools, model with credentials, knowledge bases, session storage, memory settings. 2. That dict gets splatted into `agno.agent.Agent(...)`, which gives you a real Agno agent ready to run. 3. You run it with `arun()`, capture the output, and write it back to `task.result`. 4. The `@on_task` decorator stands up an HTTP server on port 59321 and subscribes to the platform's task event stream, so any task created for this agent (from the API, Slack, Agent Studio, anywhere) is routed to your handler. ## 4. Run it locally The simplest "just boot it" command, copy-paste with zero typing: ```bash theme={"dark"} # Boots the @on_task HTTP server and subscribes to the platform event stream python3 xpander_handler.py ``` Tasks created for this agent (from any channel) will route to your handler. Hit Ctrl+C to stop. For a one-shot test with a specific prompt, no server: ```bash theme={"dark"} # Calls your handler exactly once with the prompt, prints the result, and exits python3 xpander_handler.py --invoke --prompt "What can you do?" ``` Useful in CI and for quick debugging without a web client. For an interactive dev session with extra CLI affordances (auto-reload prompts, log formatting): ```bash theme={"dark"} # Same SSE subscription as `python3 xpander_handler.py`, plus dev tooling xpander agent dev ``` What you get: 1. A local URL you can chat with. 2. **Once your dev process is running**, every task created for this agent (REST API, Slack, Agent Studio chat, MCP, any channel) is routed to your local handler, not just locally-initiated tests. 3. To iterate: edit `xpander_handler.py`, save, restart. **Routing cloud traffic to a local instance is a preview feature.** When a local instance is running via `xpander agent dev`, it takes over and all tasks route to your locally running agent instead. Only one can be active at a time. ## 5. Customize the agent (Optional) The agent created by the CLI starts blank: a default system prompt, no tools. Open `agent_instructions.json` to rewrite the role, goal, and general description; the next `xpander agent dev` syncs it to the control plane. ```json agent_instructions.json theme={"dark"} { "role": [ "You are a customer support assistant for Acme.", "Always confirm the customer's account ID before taking any action." ], "goal": [ "Resolve the customer's issue in as few turns as possible.", "Escalate to a human if the request involves a refund over $500." ], "general": "Be concise, professional, and friendly. Never invent policy details; if you don't know something, say so and offer to escalate." } ``` `role` and `goal` are arrays so you can add or remove individual statements without rewriting the prompt. `general` is a free-form description that wraps around them. Beyond that, each customization has its own page: 1. **Custom tools** wrapped with `@register_tool`. See [Custom Tools](/developers/tools/custom-tools). 2. **Prebuilt connectors** from the catalog (Slack, Gmail, GitHub, 2,000+). See [Pre-built Tools](/developers/tools/pre-built). 3. **Knowledge bases** for RAG. See [Document Management](/developers/knowledge/document-management). 4. **Memory** (session storage, user memories, agent memories). See [Memory & State](/developers/memory/session-storage). 5. **Tool hooks** for logging, metrics, and guardrails around tool calls. See [Tool Hooks](/developers/tools/tool-hooks). 6. **A different framework** (OpenAI Agents SDK, LangChain, AWS Strands). See [Frameworks](/developers/frameworks). ## Troubleshooting The handler imports before `.env` is loaded. The scaffolded handler already includes `from dotenv import load_dotenv; load_dotenv()` at the top. If you wrote your own entry point, add it before any `xpander_sdk` import. zsh expands the brackets. Quote the package name: `pip install "xpander-sdk[agno]"`. Another `@on_task` process is running. Either kill it, or set a different port for this one: `XPANDER_STREAMING_PORT=59322 python xpander_handler.py`. The `/invoke` endpoint requires the `x-api-key` header on every request. The CLI sets it for you; if you're using curl or Postman, set it explicitly to your `XPANDER_API_KEY`. When a local dev instance is running, it takes over inbound traffic. If another instance holds the slot, run `xpander agent stop` first, then start `xpander agent dev` again. `xpander agent invoke` posts to the agent's webhook and waits for a sync response. If your handler is taking more than \~30 seconds, the webhook times out even though the task keeps running on the platform. Check the task's status in the Monitor tab, or invoke through the async REST endpoint (`/v1/agents/{agent_id}/invoke/async`) for long-running tasks. ## Next steps Things you can do now that you couldn't from Agent Studio alone: Wrap a private API as a tool with `@register_tool` instead of a REST connector. Run MCP servers that need filesystem or process access. Warmup, graceful shutdown, and observability around tool calls. The SDK class names and how they map to agents, tasks, threads, and memory. What `Backend.aget_args()` actually wires up. # Agents Source: https://docs.xpander.ai/developers/sdk-reference/agents List, load, and interact with agents stored in the xpander.ai platform. The `Agents` module is your gateway to agents stored on the platform. Use it to discover what agents exist, load a specific one, and from there create tasks, invoke tools, attach knowledge bases, and inspect sessions. ```python theme={"dark"} from xpander_sdk import Agents agents = Agents() all_agents = await agents.alist() agent = await agents.aget("agent-123") task = await agent.acreate_task(prompt="Hello!") ``` ## Constructor ```python theme={"dark"} Agents(configuration: Optional[Configuration] = None) ``` | Parameter | Type | Default | Description | | --------------- | --------------- | ------- | ------------------------------------------ | | `configuration` | `Configuration` | `None` | SDK configuration. Falls back to env vars. | ## Module methods | Method | Returns | What it does | | --------------------------------------------------------- | ---------------------- | ------------------------------------------------ | | [`alist` / `list`](/developers/sdk-reference/agents#list) | `list[AgentsListItem]` | Summary list of every agent your org can access. | | [`aget` / `get`](/developers/sdk-reference/agents#get) | `Agent` | Load one agent fully (config + graph + tools). | ## `Agent` instance methods Once you've loaded an `Agent`, use its instance methods for the actual work: | Method | What it does | | -------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------- | | [`acreate_task` / `create_task`](/developers/sdk-reference/agents#create_task) | Create a new task and run it. | | [`ainvoke_tool` / `invoke_tool`](/developers/sdk-reference/agents#invoke_tool) | Invoke a single tool bound to this agent. | | [`aget_knowledge_bases` / `get_knowledge_bases`](/developers/sdk-reference/agents#knowledge-bases) | Load all knowledge bases attached to the agent. | | [`attach_knowledge_base`](/developers/sdk-reference/agents#attach_knowledge_base) | Link a knowledge base to the agent (in-memory only). | | [`knowledge_bases_retriever`](/developers/sdk-reference/agents#knowledge_bases_retriever) | Returns a `search(query, num_documents)` callable for use as a framework retriever. | | [`aget_db` / `get_db`](/developers/sdk-reference/agents#sessions) | Returns the Agno PG client backing the agent's session storage. | | [`aget_user_sessions` / `get_user_sessions`](/developers/sdk-reference/agents#sessions) | All sessions for a given end-user. | | [`aget_session` / `get_session`](/developers/sdk-reference/agents#sessions) | Load a single session. | | [`adelete_session` / `delete_session`](/developers/sdk-reference/agents#sessions) | Delete a session. | | [`aget_streaming_spec` / `get_streaming_spec`](/developers/sdk-reference/agents#streaming-spec) | Get the deployed agent's streaming URL + auth key. | | [`aget_connection_string` / `get_connection_string`](/developers/sdk-reference/agents#connection-string) | Get the agent's DB connection details. | See the [`Agent` class reference](/developers/sdk-reference/agents#agent-class) for attribute documentation. ## Quick patterns ### Find and load ```python theme={"dark"} all_agents = await agents.alist() for item in all_agents: print(item.id, item.name, item.status) agent = await all_agents[0].aload() # AgentsListItem.aload returns the full Agent # equivalent to: await agents.aget(all_agents[0].id) ``` ### Pin to a specific version ```python theme={"dark"} agent = await agents.aget("agent-123", version=4) ``` Versioning is opt-in. Without `version`, you get the latest. ### Default agent via env var ```bash theme={"dark"} export XPANDER_AGENT_ID="agent-123" ``` ```python theme={"dark"} agent = await agents.aget() # uses XPANDER_AGENT_ID ``` This works because `Agents.aget()` falls back to `Configuration.agent_id` and then to `XPANDER_AGENT_ID`. ## list `Agents.alist` returns a list of summary objects (`AgentsListItem`) for every agent visible to the configured organization. Each item carries enough metadata for display (id, name, icon, status, instructions, access scope) and a `.aload()` shortcut to fetch the full `Agent`. ```python theme={"dark"} from xpander_sdk import Agents agents = Agents() items = await agents.alist() for item in items: print(f"{item.id}\t{item.status.value}\t{item.name}") ``` #### Parameters None. #### Returns `list[AgentsListItem]` `AgentsListItem` is a lightweight summary: not the full `Agent`. Notable fields: | Field | Type | Description | | ----------------- | ------------------- | -------------------------------------------------------- | | `id` | `str` | Agent ID. | | `name` | `str` | Display name. | | `icon` | `str` | Emoji or icon identifier. | | `instructions` | `AgentInstructions` | `role`, `goal`, `general` text. | | `status` | `AgentStatus` | `DRAFT`, `ACTIVE`, or `INACTIVE`. | | `organization_id` | `str` | Owning organization. | | `created_at` | `datetime` | Creation timestamp. | | `description` | `str \| None` | Agent description. | | `access_scope` | `AgentAccessScope` | `Personal` or `Organizational`. | | `created_by` | `str \| None` | Creator user id. | | `type` | `AgentType \| None` | `Manager`, `Regular`, `A2A`, `Curl`, or `Orchestration`. | To load the full agent (graph, tools, model config, …) call `.aload()` on the item, or pass `item.id` to `agents.aget()`. ### Examples #### Filter active agents ```python theme={"dark"} items = await agents.alist() active = [i for i in items if i.status.value == "ACTIVE"] ``` #### Load all in parallel ```python theme={"dark"} import asyncio items = await agents.alist() full = await asyncio.gather(*(item.aload() for item in items)) ``` For a large org this can be heavy: prefer loading only the agents you'll actually use. #### Sync version ```python theme={"dark"} items = agents.list() ``` Same return type; blocks until the list is fetched. ### Errors `alist` raises [`ModuleException`](/developers/sdk-reference/overview#error-handling) on failure: | Status | Cause | | ------ | -------------------------------- | | 401 | Missing or invalid `api_key`. | | 403 | Wrong `organization_id`. | | 500 | Server error or network failure. | ## get `Agents.aget` loads one agent's complete configuration: instructions, model settings, the execution graph, all attached tools, knowledge-base links, and framework settings. Use this whenever you need to actually invoke an agent or inspect its config in code. ```python theme={"dark"} from xpander_sdk import Agents agents = Agents() agent = await agents.aget("agent-123") print(agent.name, agent.model_provider, agent.model_name) ``` #### Parameters | Parameter | Type | Required | Default | Description | | ---------- | ----- | -------- | --------------------------------------------- | ------------------------------------ | | `agent_id` | `str` | No¹ | `Configuration.agent_id` → `XPANDER_AGENT_ID` | Agent to load. | | `version` | `int` | No | `None` | Specific version. Latest if omitted. | ¹ The method falls back to `Configuration.agent_id` and then `XPANDER_AGENT_ID`. If none of those are set, you'll hit a 404 from the cloud. #### Returns `Agent` A full `Agent` instance. See [`Agent` class reference](/developers/sdk-reference/agents#agent-class) for attributes (instructions, framework, graph, deployment\_type, tools, knowledge\_bases, agno\_settings, etc.). ### Examples #### Latest version ```python theme={"dark"} agent = await agents.aget("agent-123") ``` #### Pinned version ```python theme={"dark"} agent = await agents.aget("agent-123", version=4) print(agent.version) # 4 ``` The version corresponds to deployment snapshots in the Workbench. Pin a version in production to avoid surprises when someone edits the agent. #### Use a default agent ID ```bash theme={"dark"} export XPANDER_AGENT_ID="agent-123" ``` ```python theme={"dark"} agent = await agents.aget() # uses XPANDER_AGENT_ID ``` This is the pattern used inside `@on_task` handlers: you don't usually pass an agent ID explicitly because the runtime injects it. #### Sync version ```python theme={"dark"} agent = agents.get("agent-123") ``` Same parameters; blocks until the agent is loaded. ### What gets loaded When you call `aget`, the SDK: 1. Fetches the agent record (`GET /agents/:id`). 2. Builds the `AgentGraph` from the graph items returned in the response. 3. Initializes a `ToolsRepository` populated with the agent's tools. 4. If any local tools (Python `@register_tool` functions) need syncing to the platform's graph, kicks off a background `sync_local_tools` task: non-blocking. You can read `agent.graph` to inspect the tool/connector wiring, `agent.tools.list` for all tools, `agent.knowledge_bases` for KB links, and `agent.mcp_servers` for the configured MCP servers. ### Errors `aget` raises [`ModuleException`](/developers/sdk-reference/overview#error-handling) on failure: | Status | Cause | | ------ | -------------------------------------------------- | | 404 | Agent not found, or wrong organization. | | 403 | Agent exists but isn't accessible to your account. | | 500 | Server error or network failure. | ## create\_task `Agent.acreate_task` creates a new task on the platform and returns a `Task` object you can save, stream, or stop. This is the primary way to invoke an agent from code. ```python theme={"dark"} from xpander_sdk import Agents agent = await Agents().aget("agent-123") task = await agent.acreate_task(prompt="Summarize this document.") print(task.id, task.status.value) ``` The newly-created task is queued by the platform; the agent worker (either a managed cloud worker or your local `@on_task` handler) picks it up and executes it. #### Parameters | Parameter | Type | Required | Default | Description | | ------------------------------ | ------------------------ | -------- | --------- | ----------------------------------------------------------------------- | | `prompt` | `str` | No | `""` | Natural-language input. | | `existing_task_id` | `str` | No | `None` | Continue an existing task. Reuses memory thread. | | `file_urls` | `list[str]` | No | `[]` | URLs of files to attach (PDFs, images, CSVs, …). | | `user_details` | `User` | No | `None` | End-user context (id, email, timezone) for memory and connector auth. | | `agent_version` | `str` | No | `None` | Pin to a specific agent version. | | `tool_call_payload_extension` | `dict` | No | `None` | Extra fields merged into every tool-call payload. | | `source` | `str` | No | `"sdk"` | Origin tag (`"webhook"`, `"slack"`, …). | | `worker_id` | `str` | No | `None` | Pin execution to a specific worker. | | `run_locally` | `bool` | No | `False` | Mark the task as locally executed (skips cloud dispatch). | | `output_format` | `OutputFormat` | No | `None` | `Text`, `Markdown`, `Json`, or `Voice`. | | `output_schema` | `dict` | No | `None` | JSON schema (paired with `OutputFormat.Json`). | | `events_streaming` | `bool` | No | `False` | Enables SSE streaming via `task.aevents()`. | | `additional_context` | `str` | No | `None` | Extra context appended to the system prompt. | | `instructions_override` | `str` | No | `None` | Extra instructions appended for this run only. | | `test_run_node_id` | `str` | No | `None` | (Internal) Workflow node to execute in test mode. | | `user_oidc_token` | `str` | No | `None` | OIDC token for connector pre-auth. | | `expected_output` | `str` | No | `None` | Description of expected output shape. | | `mcp_servers` | `list[MCPServerDetails]` | No | `[]` | Per-task MCP servers (in addition to the agent's configured servers). | | `triggering_agent_id` | `str` | No | `None` | ID of the agent that triggered this task (for sub-agent tracking). | | `title` | `str` | No | `None` | Display title in the dashboard. | | `think_mode` | `ThinkMode` | No | `Default` | `Default` or `Harder`. Toggles extended reasoning. | | `disable_attachment_injection` | `bool` | No | `False` | Skip auto-injecting human-readable file content into the prompt. | | `return_metrics` | `bool` | No | `False` | Return metrics in the task. Only valid for Workflow → Agent invocation. | | `user_tokens` | `dict` | No | `None` | Pre-computed user tokens injected for MCP auth. | #### Returns `Task` The created `Task`. See [`Task` class reference](/developers/sdk-reference/tasks#task-class). The task starts in status `Pending`. It moves through `Executing` → `Completed` (or `Error` / `Failed` / `Stopped`) as the worker runs it. ### Examples #### With files ```python theme={"dark"} task = await agent.acreate_task( prompt="Find action items in this meeting.", file_urls=[ "https://example.com/recording.mp3", "https://example.com/transcript.pdf", ], ) ``` #### Structured output ```python theme={"dark"} from xpander_sdk import OutputFormat task = await agent.acreate_task( prompt="Extract company name and revenue from the press release.", file_urls=["https://example.com/press-release.pdf"], output_format=OutputFormat.Json, output_schema={ "type": "object", "properties": { "company": {"type": "string"}, "revenue_usd": {"type": "number"}, }, "required": ["company"], }, ) ``` #### Streaming ```python theme={"dark"} task = await agent.acreate_task( prompt="Long-running analysis…", events_streaming=True, ) async for event in task.aevents(): print(event.type, event.data) ``` `events_streaming=True` is required to use `task.aevents()`. See [`task.events`](/developers/sdk-reference/tasks#events). #### Continue a thread ```python theme={"dark"} task = await agent.acreate_task( existing_task_id="task_abc123", prompt="What was the conclusion?", ) ``` The new task reuses the prior task's memory thread, so the agent has full context. #### Per-end-user ```python theme={"dark"} from xpander_sdk import User task = await agent.acreate_task( prompt="Summarize my unread email.", user_details=User( id="user_42", email="alex@example.com", first_name="Alex", timezone="America/New_York", ), ) ``` `user_details.id` scopes user-memory and connector auth (e.g. each end user's Gmail OAuth token). #### Add an MCP server just for this task ```python theme={"dark"} from xpander_sdk import MCPServerDetails, MCPServerType, MCPServerTransport task = await agent.acreate_task( prompt="Query our internal docs.", mcp_servers=[ MCPServerDetails( type=MCPServerType.Remote, name="internal-docs", url="https://mcp.internal.acme.com", transport=MCPServerTransport.HTTP_Transport, ), ], ) ``` Per-task MCP servers stack on top of the agent's persistent MCP configuration. #### Pin a version ```python theme={"dark"} task = await agent.acreate_task( prompt="Run with the locked v3 prompt", agent_version="3", ) ``` ### Sync version ```python theme={"dark"} task = agent.create_task(prompt="Hello!") ``` Same parameters; blocks until the task is created. Don't call from inside an event loop. ### Errors Raises [`ModuleException`](/developers/sdk-reference/overview#error-handling) on failure: | Status | Cause | | --------- | ----------------------------------------------------------------- | | 400 | Invalid input (bad output schema, malformed `mcp_servers`, etc.). | | 401 / 403 | Auth failure. | | 404 | Agent doesn't exist. | | 500 | Server error. | ## invoke\_tool `Agent.ainvoke_tool` runs a single tool from the agent's `ToolsRepository` and returns a `ToolInvocationResult`. Use it when you want to test a tool, or when you're building an agent loop yourself and the framework's tool dispatcher isn't a good fit. ```python theme={"dark"} from xpander_sdk import Agents agent = await Agents().aget("agent-123") weather_tool = agent.tools.get_tool_by_id("get_weather") result = await agent.ainvoke_tool( tool=weather_tool, payload={"city": "New York"}, ) print(result.is_success, result.result) ``` #### Parameters | Parameter | Type | Required | Default | Description | | ------------------- | ------ | -------- | ------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `tool` | `Tool` | Yes | – | A `Tool` instance, typically from `agent.tools.get_tool_by_id(...)` or `agent.tools.list`. | | `payload` | `Any` | Yes | – | Tool input. Validated against `tool.schema` before execution. Local tools registered with `@register_tool` take their arguments flat, as in the example above. Platform connector tools take the grouped form instead — `{"body_params": {...}, "query_params": {...}, "path_params": {...}, "headers": {...}}` — matching [Invoke Connector Operation](/api-reference/v1/tools/invoke-connector-operation). Check `tool.schema` when unsure. | | `payload_extension` | `dict` | No | `{}` | Extra fields deep-merged into the payload (e.g. headers, auth params). | | `task_id` | `str` | No | `None` | Associate the invocation with a specific task (for activity logging). | | `tool_call_id` | `str` | No | `None` | Correlation ID for this call (matches LLM tool-call IDs). | #### Returns `ToolInvocationResult` | Field | Type | Description | | -------------- | ------------- | ------------------------------------------------------------------ | | `tool_id` | `str` | The tool's id. | | `tool_call_id` | `str \| None` | The correlation ID, if passed. | | `task_id` | `str \| None` | The task ID, if passed. | | `payload` | `Any` | The payload that was sent. | | `result` | `Any` | The tool's response. Shape depends on the tool. | | `is_success` | `bool` | `True` when the call returned 2xx. | | `is_error` | `bool` | `True` when the call raised or returned an error status. | | `status_code` | `int` | HTTP status from the remote tool, or `500` for client-side errors. | | `is_local` | `bool` | `True` for tools registered via `@register_tool`. | `is_success` and `is_error` are mutually exclusive in normal operation; check `is_error` first. ### Examples #### With `payload_extension` ```python theme={"dark"} result = await agent.ainvoke_tool( tool=weather_tool, payload={"city": "Tokyo"}, payload_extension={"headers": {"X-Trace-ID": "abc-123"}}, ) ``` `payload_extension` is deep-merged with `payload`, so nested objects compose naturally. #### Local Python tools Tools registered with `@register_tool` are invoked locally (the `fn` runs in-process) and pass through the same `ToolInvocationResult` interface: ```python theme={"dark"} from xpander_sdk import register_tool @register_tool def add(a: int, b: int) -> int: """Add two numbers.""" return a + b # 'add' is now in the global tool registry agent = await Agents().aget("agent-123") add_tool = agent.tools.get_tool_by_id("add") result = await agent.ainvoke_tool(tool=add_tool, payload={"a": 2, "b": 3}) result.result # 5 result.is_local # True ``` See [`@register_tool`](/developers/sdk-reference/tools#register_tool-classmethod) for details. #### Inside an `@on_task` handler ```python theme={"dark"} from xpander_sdk import on_task from xpander_sdk.modules.tasks.sub_modules.task import Task @on_task async def handler(task: Task) -> Task: agent = await Agents().aget(task.agent_id) tool = agent.tools.get_tool_by_id("my_tool") result = await agent.ainvoke_tool( tool=tool, payload={"x": 1}, task_id=task.id, # links the invocation to this task in the dashboard ) task.result = str(result.result) return task ``` Passing `task_id` ensures the invocation appears in `task.aget_activity_log()`. #### Sync version ```python theme={"dark"} result = agent.invoke_tool(tool=weather_tool, payload={"city": "Berlin"}) ``` ### Notes * Payload validation: if `payload` doesn't match `tool.schema`, the SDK raises `ValueError` (not `ModuleException`). Catch it separately if you're invoking with untrusted input. * Lifecycle hooks ([`@on_tool_before` / `@on_tool_after` / `@on_tool_error`](/developers/sdk-reference/decorators#@on_tool_before-/-@on_tool_after-/-@on_tool_error)) fire around the invocation. * For invocations outside an agent context, use `tool.get_invocation_function()` instead: it requires a `connector_id` and `operation_id` resolved via `tools.aload_tool_by_id(...)`. ## Knowledge bases Agents can have knowledge bases linked to them in the Workbench. From code, you can attach more, load the `KnowledgeBase` objects, or build a retriever callable for use as a framework retriever. ```python theme={"dark"} agent = await agents.aget("agent-123") # Inspect linked KBs for kb_link in agent.knowledge_bases: print(kb_link.id) # Load full KnowledgeBase objects kbs = await agent.aget_knowledge_bases() for kb in kbs: print(kb.name, kb.total_documents) ``` ### `aget_knowledge_bases` Load every `KnowledgeBase` linked to the agent, in parallel. ```python theme={"dark"} kbs = await agent.aget_knowledge_bases() ``` #### Returns `list[KnowledgeBase]` A list of full `KnowledgeBase` objects. See [`KnowledgeBase`](/developers/sdk-reference/knowledge-bases#knowledgebase-class) for the methods you can call on each. #### Sync version ```python theme={"dark"} kbs = agent.get_knowledge_bases() ``` ### `attach_knowledge_base` Link a knowledge base to the agent on the in-memory instance. Pass either a `KnowledgeBase` object or a knowledge-base ID. ```python theme={"dark"} from xpander_sdk import KnowledgeBases kb = await KnowledgeBases().aget("kb-456") agent.attach_knowledge_base(knowledge_base=kb) # or by id only agent.attach_knowledge_base(knowledge_base_id="kb-456") ``` #### Parameters | Parameter | Type | Required | Description | | ------------------- | --------------- | -------- | --------------------------- | | `knowledge_base` | `KnowledgeBase` | No | A `KnowledgeBase` instance. | | `knowledge_base_id` | `str` | No | Knowledge-base ID. | You must pass at least one of the two. If both are passed, `knowledge_base.id` is used. `attach_knowledge_base` only updates the agent in memory. To persist the link, save the agent through the platform (e.g. via the API or the Workbench UI). The runtime instance will use the link for the current session, but it won't survive a re-load. ### `knowledge_bases_retriever` Returns a `search(query, agent=None, num_documents=5)` callable that searches every linked KB and returns top-N results sorted by score. This is the form Agno expects as a custom retriever. ```python theme={"dark"} retriever = agent.knowledge_bases_retriever() results = retriever(query="quarterly revenue", num_documents=10) for r in results: print(r["score"], r["content"][:100]) ``` #### Returned callable signature ```python theme={"dark"} def search( query: str, agent: Optional[Any] = None, # ignored; for compat with framework retrievers num_documents: int = 5, **kwargs, ) -> list[dict] | None ``` | Parameter | Type | Default | Description | | --------------- | ----- | ------- | ----------------------------------------------------------------------- | | `query` | `str` | – | Search query. | | `agent` | `Any` | `None` | Ignored. Present for compatibility with framework retriever signatures. | | `num_documents` | `int` | `5` | Top-K to return. If `0` is passed, defaults to `10`. | Each result is a dict from `KnowledgeBaseSearchResult.model_dump()`: ```python theme={"dark"} {"content": "...", "score": 0.86} ``` The retriever swallows errors and returns `[]` if the search fails: useful for embedding into framework pipelines that shouldn't crash on retrieval errors. ### Patterns #### Wire as the Agno knowledge ```python theme={"dark"} from xpander_sdk import Backend from agno.agent import Agent as AgnoAgent agent = await agents.aget("agent-123") backend = Backend() args = await backend.aget_args(agent=agent) # args["knowledge"] is already populated when the agent has KBs linked. agno_agent = AgnoAgent(**args) ``` `Backend.aget_args` already wires the retriever for you: you don't usually need to call `knowledge_bases_retriever()` directly. Use it only when bypassing the Backend dispatcher. #### Add a KB on the fly ```python theme={"dark"} from xpander_sdk import KnowledgeBases kbs = KnowledgeBases() new_kb = await kbs.acreate(name="Q4 reports", description="Quarterly earnings") await new_kb.aadd_documents([ "https://example.com/Q4-2024.pdf", "https://example.com/Q4-2025.pdf", ]) agent.attach_knowledge_base(knowledge_base=new_kb) ``` After `attach_knowledge_base`, `agent.aget_knowledge_bases()` includes the new KB in the list. ## Sessions Agents using the Agno framework with `agno_settings.session_storage = True` persist their session history to a Postgres database managed by the platform. The SDK exposes that database via `Agent.aget_db()` plus a small set of helpers for session CRUD. Sessions are only available for Agno agents with session storage enabled. Calling these methods on other agents raises `NotImplementedError` (wrong framework) or `LookupError` (storage disabled). The Agno extras must be installed: `pip install xpander-sdk[agno]`. ### `aget_db` Returns the Agno Postgres client backing the agent's session storage. ```python theme={"dark"} db = await agent.aget_db() # async client (AsyncPostgresDb) db_sync = await agent.aget_db(async_db=False) # sync client (PostgresDb) ``` #### Parameters | Parameter | Type | Default | Description | | ---------- | ------ | ------- | ---------------------------------------------------------- | | `async_db` | `bool` | `True` | When `False`, returns the synchronous `PostgresDb` client. | #### Returns `agno.db.postgres.AsyncPostgresDb` (or `PostgresDb` if `async_db=False`). The client is namespaced to the agent's schema, so different agents don't share a session table. The connection URI is fetched (and cached) via `agent.aget_connection_string()` on the first call. #### Sync version ```python theme={"dark"} db = agent.get_db() # equivalent to aget_db(async_db=False) ``` ### `aget_user_sessions` Load all sessions for a given end-user. ```python theme={"dark"} sessions = await agent.aget_user_sessions(user_id="user_42") for s in sessions: print(s.session_id, s.created_at) ``` #### Parameters | Parameter | Type | Required | Description | | --------- | ----- | -------- | -------------------------------------------------------------------- | | `user_id` | `str` | Yes | End-user identifier (matches `user_details.id` from `acreate_task`). | #### Returns A list of session records. The exact type comes from Agno's `db.get_sessions(...)`: fields include `session_id`, `user_id`, `agent_id` (or `team_id` for Team mode), and timestamps. The query caps results at 50 sessions per call. For Team agents (`agent.is_a_team == True`), this returns `SessionType.TEAM` records; otherwise `SessionType.AGENT`. #### Sync version ```python theme={"dark"} sessions = agent.get_user_sessions(user_id="user_42") ``` ### `aget_session` Load a single session by ID. ```python theme={"dark"} session = await agent.aget_session(session_id="sess_456") ``` #### Parameters | Parameter | Type | Required | Description | | ------------ | ----- | -------- | ------------------- | | `session_id` | `str` | Yes | Session identifier. | #### Returns The session record, or `None` if it doesn't exist. #### Sync version ```python theme={"dark"} session = agent.get_session(session_id="sess_456") ``` ### `adelete_session` Delete a session. ```python theme={"dark"} await agent.adelete_session(session_id="sess_456") ``` #### Parameters | Parameter | Type | Required | Description | | ------------ | ----- | -------- | ------------------ | | `session_id` | `str` | Yes | Session to delete. | #### Sync version ```python theme={"dark"} agent.delete_session(session_id="sess_456") ``` ### Errors All session methods raise: * `NotImplementedError`: agent isn't using Agno. * `LookupError`: Agno is configured but `agno_settings.session_storage` is `False`. * `ImportError`: Agno extras not installed (run `pip install xpander-sdk[agno]`). * `ValueError`: connection URI couldn't be resolved. ### Patterns #### Inspect recent sessions for a user ```python theme={"dark"} sessions = await agent.aget_user_sessions(user_id="user_42") for s in sorted(sessions, key=lambda x: x.created_at, reverse=True)[:5]: print(f"{s.session_id}: {s.created_at}") ``` #### Wipe all sessions for a user ```python theme={"dark"} sessions = await agent.aget_user_sessions(user_id="user_42") for s in sessions: await agent.adelete_session(session_id=s.session_id) ``` `aget_user_sessions` returns at most 50 records per call, so loop until empty for users with many sessions. #### Drop into the Agno DB directly ```python theme={"dark"} db = await agent.aget_db() # Now use any AsyncPostgresDb method: read messages, custom queries, etc. session = await db.get_session(session_id="sess_456", session_type=...) ``` Use this when the four convenience methods don't cover what you need; the Agno DB client has a richer API. ## Agent class `Agent` is the rich object returned by `Agents.aget()` and `AgentsListItem.aload()`. It carries the agent's full stored configuration, plus methods for creating tasks, invoking tools, and managing sessions. ```python theme={"dark"} from xpander_sdk import Agents agent = await Agents().aget("agent-123") print(agent.name) print(agent.model_provider, agent.model_name) print(agent.deployment_type.value) # "serverless" print(len(agent.tools.list)) ``` ### Class methods #### `Agent.aload(agent_id, configuration=None, version=None) -> Agent` Load an agent by ID. This is what `Agents.aget()` calls internally. Use the module-level `agents.aget(...)` in normal code; `Agent.aload(...)` is for places where you have a `Configuration` but no `Agents` instance. ```python theme={"dark"} from xpander_sdk import Agent, Configuration config = Configuration(api_key="...", organization_id="...") agent = await Agent.aload(agent_id="agent-123", configuration=config) ``` | Parameter | Type | Required | Default | Description | | --------------- | --------------- | -------- | ------- | ------------------------------------- | | `agent_id` | `str` | Yes | – | Agent to load. | | `configuration` | `Configuration` | No | `None` | SDK config. Uses defaults if omitted. | | `version` | `int` | No | `None` | Specific version. Latest if omitted. | The sync sibling is `Agent.load(...)`. ### Attributes | Attribute | Type | Description | | ----------------------- | ------------------------------------------------------------------------- | -------------------------------------------------------------------------------------- | | `id` | `str` | Agent identifier. | | `organization_id` | `str` | Owning organization. | | `name` | `str` | Display name. | | `description` | `str \| None` | Long description. | | `unique_name` | `str` | URL-safe slug. | | `icon` | `str` | Emoji or icon. Defaults to `"🚀"`. | | `status` | `AgentStatus` | `DRAFT`, `ACTIVE`, or `INACTIVE`. | | `version` | `int` | Loaded version. | | `created_by` | `str \| None` | Creator user id. | | `created_at` | `datetime \| None` | Creation timestamp. | | `access_scope` | `AgentAccessScope` | `Personal` or `Organizational`. | | `type` | `AgentType \| None` | `Manager`, `Regular`, `A2A`, `Curl`, `Orchestration`. | | `framework` | `Framework` | Always `Agno` today. Other values reserved. | | `deployment_type` | `AgentDeploymentType` | `Serverless`. | | `instructions` | `AgentInstructions` | `role: list[str]`, `goal: list[str]`, `general: str`. | | `graph` | `AgentGraph` | Execution graph (source nodes, tools, sub-agents, MCP). | | `tools` | `ToolsRepository` | Repository of attached tools. See [Tools Repository](/developers/sdk-reference/tools). | | `knowledge_bases` | `list[AgentKnowledgeBase]` | Linked knowledge bases (id pointers). | | `model_provider` | `str` | e.g. `"openai"`, `"anthropic"`, `"bedrock"`. | | `model_name` | `str` | e.g. `"gpt-4o"`, `"claude-sonnet-4"`. | | `llm_reasoning_effort` | `LLMReasoningEffort` | `Low`, `Medium`, or `High`. | | `llm_api_base` | `str \| None` | Override for the LLM endpoint (Bedrock / Azure / Ollama). | | `llm_extra_headers` | `dict[str, str]` | Extra headers for LLM calls. | | `output_format` | `OutputFormat` | Default output format. | | `output_schema` | `dict \| None` | Default JSON schema (used when `output_format == Json`). | | `expected_output` | `str` | Description of the expected output. | | `agno_settings` | `AgnoSettings` | Memory, tool-call limits, guardrails, reasoning settings. | | `webhook_url` | `str \| None` | Configured webhook for completed tasks. | | `connectivity_details` | `AIAgentConnectivityDetailsA2A \| AIAgentConnectivityDetailsCurl \| dict` | Wire details for `A2A` and `Curl` agent types. | | `voice_id` | `str \| None` | Voice ID for `OutputFormat.Voice`. | | `task_level_strategies` | `TaskLevelStrategies \| None` | Retry / iterative / stop strategies and per-day caps. | | `orchestration_nodes` | `list[OrchestrationNode]` | Sub-nodes for orchestration agents. | | `notification_settings` | `NotificationSettings` | Alerting config. | | `use_oidc_pre_auth` | `bool` | Whether the agent uses OIDC pre-auth tokens. | | `pre_auth_audiences` | `list[str]` | OIDC audiences for pre-auth. | | `using_nemo` | `bool` | Whether NeMo is in use. | | `deep_planning` | `bool` | Whether deep planning is enabled. | | `enforce_deep_planning` | `bool` | Strict plan enforcement. | | `llm_credentials` | `LLMCredentials \| None` | Per-agent LLM credentials, if overridden. | ### Computed properties | Property | Type | Description | | ------------------------- | ------------------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `mcp_servers` | `list[MCPServerDetails]` | MCP servers configured in the graph. | | `output` | `AgentOutput` | Resolved output configuration (Pydantic schema, markdown flag, JSON-mode flag). | | `search_knowledge` | `bool` | `True` when the agent has at least one linked knowledge base. | | `is_a_team` | `bool` | Truthy when the agent has sub-agents (Manager / Team mode). Returns an empty list rather than `False` when there are none, so test it for truthiness rather than comparing to `False`. | | `is_active` | `bool` | `agent.status == AgentStatus.ACTIVE`. | | `sanitized_name` | `str` | `name` munged to a valid Python identifier. | | `strands_tools` | `list` | Strands-formatted tool wrappers. | | `openai_agents_sdk_tools` | `list` | OpenAI Agents SDK-formatted tool wrappers. | ### Instance methods | Method | Reference | | ---------------------------------------------- | ----------------------------------------------------------------------------- | | `acreate_task` / `create_task` | [Create a task](/developers/sdk-reference/agents#create_task) | | `ainvoke_tool` / `invoke_tool` | [Invoke a tool](/developers/sdk-reference/agents#invoke_tool) | | `aget_knowledge_bases` / `get_knowledge_bases` | [Knowledge bases](/developers/sdk-reference/agents#knowledge-bases) | | `attach_knowledge_base` | [Knowledge bases](/developers/sdk-reference/agents#attach_knowledge_base) | | `knowledge_bases_retriever` | [Knowledge bases](/developers/sdk-reference/agents#knowledge_bases_retriever) | | `aget_db` / `get_db` | [Sessions](/developers/sdk-reference/agents#sessions) | | `aget_user_sessions` / `get_user_sessions` | [Sessions](/developers/sdk-reference/agents#sessions) | | `aget_session` / `get_session` | [Sessions](/developers/sdk-reference/agents#sessions) | | `adelete_session` / `delete_session` | [Sessions](/developers/sdk-reference/agents#sessions) | #### Streaming spec `agent.aget_streaming_spec() -> StreamingSpecResponse`: returns the deployed agent's streaming URL and an API key for its `/invoke` endpoint. Useful when you want to bypass the SSE channel and POST directly to a deployed worker. ```python theme={"dark"} spec = await agent.aget_streaming_spec() print(spec.url) # https://.containers.xpander.ai/invoke print(spec.api_key) # auth token for the /invoke endpoint ``` `StreamingSpecResponse` has two fields: `url` (str | None) and `api_key` (str | None). Both can be `None` if the agent isn't deployed yet. #### Connection string `agent.aget_connection_string() -> DatabaseConnectionString`: returns DB connection details for agents using session storage. The result is cached on the instance after the first call. ```python theme={"dark"} conn = await agent.aget_connection_string() print(conn.connection_uri.uri) ``` `DatabaseConnectionString` has `id`, `name`, `organization_id`, and `connection_uri.uri` (a Postgres-compatible URI). #### sync\_local\_tools `await agent.sync_local_tools(tools=[...])`: pushes locally-decorated `@register_tool(add_to_graph=True)` tools to the platform's graph. Called automatically when `Agent.aload` detects unsynced tools, so you rarely need to invoke it directly. # Backend Source: https://docs.xpander.ai/developers/sdk-reference/backend The Backend module bridges your code and a stored agent configuration. The `Backend` module is the bridge between your code and an agent stored in the xpander.ai platform. It does three things: 1. **Resolves runtime arguments** for your AI framework: `aget_args(agent_id=..., task=task)` returns kwargs you can spread directly into Agno (or another supported framework's) agent constructor. 2. **Invokes agents directly**: `ainvoke_agent(agent_id=..., prompt=...)` is shorthand for "load the agent, create a task." Useful when you don't need framework-level control. 3. **Reports externally executed runs**: `areport_external_task(...)` lets you log a run that happened outside the platform (e.g. in a queue worker or another runtime) so it shows up in the same task history and metrics as platform-managed runs. ```python theme={"dark"} from xpander_sdk import Backend backend = Backend() ``` ## Constructor ```python theme={"dark"} Backend(configuration: Optional[Configuration] = None) ``` | Parameter | Type | Default | Description | | --------------- | --------------- | ------- | ------------------------------------------ | | `configuration` | `Configuration` | `None` | SDK configuration. Falls back to env vars. | When called without arguments, the module reads `XPANDER_API_KEY`, `XPANDER_ORGANIZATION_ID`, and `XPANDER_BASE_URL` from the environment. ## Methods | Method | What it does | | ---------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------- | | [`ainvoke_agent` / `invoke_agent`](/developers/sdk-reference/backend#invoke_agent) | Load an agent and create a task in one call. Returns a `Task`. | | [`aget_args` / `get_args`](/developers/sdk-reference/backend#get_args) | Resolve framework-specific kwargs (model, system prompt, tools, memory, …) from a stored agent configuration. | | [`areport_external_task` / `report_external_task`](/developers/sdk-reference/backend#report_external_task) | Record an external execution (run outside the platform) so it appears in task history. | ## Typical pattern ```python theme={"dark"} from xpander_sdk import Backend, on_task from xpander_sdk.modules.tasks.sub_modules.task import Task from agno.agent import Agent as AgnoAgent backend = Backend() @on_task async def handler(task: Task) -> Task: args = await backend.aget_args( agent_id=task.agent_id, agent_version=task.agent_version, task=task, ) agno_agent = AgnoAgent(**args) result = await agno_agent.arun(input=task.to_message()) task.result = result.content return task ``` `@on_task` listens for incoming task events from the platform; the handler resolves framework args for the *current* task, builds an Agno agent, runs it, and stores the result on the task. The platform records status, metrics, and tool calls automatically. ## Environment variable shortcut Set `XPANDER_AGENT_ID` and you can omit `agent_id` from every Backend call: ```bash theme={"dark"} export XPANDER_AGENT_ID="agent-123" ``` ```python theme={"dark"} backend = Backend() args = await backend.aget_args() # uses XPANDER_AGENT_ID task = await backend.ainvoke_agent(prompt="Hello") # same ``` Explicit arguments always override the env var. ## get\_args `Backend.aget_args` returns a dictionary of framework-ready keyword arguments for a stored agent. Spread the result directly into an Agno (or other supported framework's) constructor: the dict already contains the model, system prompt, tools, memory settings, knowledge-base retrievers, and guardrails configured in the Workbench. ```python theme={"dark"} from xpander_sdk import Backend, Task, on_task from agno.agent import Agent as AgnoAgent @on_task async def handler(task: Task) -> Task: backend = Backend(configuration=task.configuration) args = await backend.aget_args(task=task) agno_agent = AgnoAgent(**args) result = await agno_agent.arun(input=task.to_message()) task.result = result.content return task ``` This is the primary integration point for code-based agents. Call it once per task, inside `@on_task`, passing the `task` so the resolved kwargs carry that run's input, files, and output schema alongside the latest stored configuration. #### Parameters | Parameter | Type | Required | Default | Description | | ---------------------- | ---------------- | -------- | -------------------------- | ------------------------------------------------------------------------------------------------------------- | | `agent_id` | `str` | No¹ | `XPANDER_AGENT_ID` env var | Agent ID. Required if `agent` is not provided. | | `agent` | `Agent` | No¹ | `None` | A pre-loaded `Agent` instance. Takes precedence over `agent_id`. | | `agent_version` | `int` | No | `None` | Specific version to load. Latest if omitted. | | `task` | `Task` | Yes² | `None` | The current task. Supplies the run's input, files, and output schema on top of the stored configuration. | | `override` | `dict[str, Any]` | No | `None` | Final overrides merged into the resolved kwargs. | | `tools` | `list[Callable]` | No | `None` | Extra Python callables added to the agent's tool list. | | `is_async` | `bool` | No | `True` | (async only) Whether you'll run the framework agent in an async context. Affects how local tools are wrapped. | | `auth_events_callback` | `Callable` | No | `None` | Per-call callback for MCP/OAuth authentication events. See [Authentication events](#authentication-events). | ¹ Either `agent_id` or `agent` must be resolvable. If neither is passed, the method falls back to `XPANDER_AGENT_ID`. ² Optional in the signature, but pass it. The resolved kwargs are built from the task, so call `aget_args` from inside `@on_task` where a `Task` is in scope. #### Returns `dict[str, Any]` A dictionary of framework-ready kwargs. The exact keys depend on the agent's framework (currently always Agno): ```python theme={"dark"} { "name": "Sales Assistant", "agent_id": "agent-123", "model": , "instructions": "...", "tools": [, , ...], "knowledge": , "memory_manager": , "db": , "guardrails": [...], "user_id": "...", "session_id": "...", # ...framework-specific keys } ``` You don't need to read these: pass them straight to the framework's constructor. ### Examples #### Inside `@on_task` ```python theme={"dark"} from xpander_sdk import Backend, on_task from xpander_sdk.modules.tasks.sub_modules.task import Task from agno.agent import Agent as AgnoAgent backend = Backend() @on_task async def handler(task: Task) -> Task: args = await backend.aget_args( agent_id=task.agent_id, agent_version=task.agent_version, task=task, ) agno_agent = AgnoAgent(**args) result = await agno_agent.arun( input=task.to_message(), files=task.get_files(), images=task.get_images(), ) task.result = result.content return task ``` Passing `task=task` enriches the args with task-specific context (session id, user id, output schema), so memory and structured output work transparently. #### Pre-loaded agent (avoid re-fetching) ```python theme={"dark"} from xpander_sdk import Agents, Backend agents = Agents() backend = Backend() agent = await agents.aget("agent-123") # fetched once, reused # Many tasks for the same agent: pass `agent` instead of `agent_id` for prompt in prompts: args = await backend.aget_args(agent=agent, task=task, override={"name": "batch-worker"}) ... ``` `agent` takes precedence over `agent_id`. This avoids a fresh `GET /agents/:id` call each time you build framework args. #### Override resolved kwargs ```python theme={"dark"} args = await backend.aget_args( agent_id="agent-123", task=task, override={ "show_tool_calls": True, "markdown": False, }, ) ``` `override` is shallow-merged after the framework dispatcher builds its kwargs, so anything you set wins. #### Add extra tools ```python theme={"dark"} def lookup_internal_id(employee_email: str) -> str: """Look up an employee's internal ID from email.""" ... args = await backend.aget_args( agent_id="agent-123", task=task, tools=[lookup_internal_id], ) ``` The callable is appended to the agent's tool list for this run only: it isn't persisted to the platform. For permanent tools, register with [`@register_tool`](/developers/sdk-reference/tools#register_tool-classmethod) instead. ### Authentication events When an agent uses MCP servers or connectors that require OAuth, the framework emits `auth_event` updates while the user authenticates. Register a callback to handle the OAuth URL or token-ready signals: #### Per-call callback ```python theme={"dark"} from xpander_sdk import Backend from xpander_sdk.modules.agents.sub_modules.agent import Agent from xpander_sdk.modules.tasks.sub_modules.task import Task, TaskUpdateEvent async def on_auth(agent: Agent, task: Task, event: TaskUpdateEvent): print(f"Auth required: {event.data}") # Show event.data['url'] to the user, or kick off your OAuth flow backend = Backend() args = await backend.aget_args( agent_id="agent-123", task=task, auth_events_callback=on_auth, ) ``` #### Globally with `@on_auth_event` ```python theme={"dark"} from xpander_sdk import on_auth_event @on_auth_event async def handle_auth(agent, task, event): print(f"[GLOBAL] {agent.name}: {event.data}") # No need to pass it: the decorator auto-registers args = await backend.aget_args(agent_id="agent-123", task=task) ``` You can combine both: decorated handlers are always invoked, and `auth_events_callback` adds a one-off handler on top. See [`@on_auth_event`](/developers/sdk-reference/decorators#@on_auth_event) for details. ### Sync version ```python theme={"dark"} args = backend.get_args(agent_id="agent-123", task=task) ``` Same parameters minus `is_async` (sync wrapper hard-codes it to `False` so local tools are wrapped synchronously). Don't call from inside a running event loop. ## invoke\_agent `Backend.ainvoke_agent` (and its sync sibling `invoke_agent`) is shorthand for "load the agent and create a task." Internally it calls `Agents.aget(agent_id)` followed by `Agent.acreate_task(...)`, returning the resulting `Task`. Use this when you want to invoke an agent from outside the `@on_task` runtime: for example, from a webhook handler, a script, or another agent. If `prompt` happens to be a JSON string containing `xpander_task_id`, the method short-circuits and returns the existing task instead of creating a new one. This is how the platform passes task continuations through chat-style integrations. ```python theme={"dark"} from xpander_sdk import Backend backend = Backend() task = await backend.ainvoke_agent( agent_id="agent-123", prompt="Summarize the latest sales report", ) print(task.id, task.status) ``` #### Parameters | Parameter | Type | Required | Default | Description | | ----------------------------- | -------------- | -------- | -------------------------- | ----------------------------------------------------------------------------------------- | | `agent_id` | `str` | No | `XPANDER_AGENT_ID` env var | Agent to invoke. Falls back to env var if omitted. | | `prompt` | `str` | No | `""` | Natural-language input for the agent. | | `existing_task_id` | `str` | No | `None` | Continue an existing task instead of creating a new one. | | `file_urls` | `list[str]` | No | `None` | URLs of files to attach (PDFs, images, CSVs, …). | | `user_details` | `User` | No | `None` | End-user context for memory and personalization. | | `agent_version` | `str` | No | `None` | Pin a specific agent version. Defaults to the latest. | | `tool_call_payload_extension` | `dict` | No | `None` | Extra fields merged into every tool-call payload. | | `source` | `str` | No | `"sdk"` | Origin tag stored on the task (e.g. `"webhook"`, `"slack"`). | | `worker_id` | `str` | No | `None` | Pin execution to a specific worker. | | `run_locally` | `bool` | No | `False` | Mark the task as locally executed (skips cloud worker dispatch). | | `output_format` | `OutputFormat` | No | `None` | `Text`, `Markdown`, `Json`, or `Voice`. | | `output_schema` | `dict` | No | `None` | JSON schema for structured output (paired with `OutputFormat.Json`). | | `events_streaming` | `bool` | No | `False` | Enable SSE streaming via `task.aevents()`. | | `additional_context` | `str` | No | `None` | Extra context appended to the system prompt for this run. | | `expected_output` | `str` | No | `None` | Description of the expected output shape (used by some frameworks for self-verification). | #### Returns `Task` The created `Task` object, populated with the platform-assigned `id` and an initial `status` of `pending`. See [`Task`](/developers/sdk-reference/tasks#task-class) for the full attribute list. ### Examples #### Attach files ```python theme={"dark"} task = await backend.ainvoke_agent( agent_id="agent-123", prompt="Find action items from this meeting recording.", file_urls=[ "https://example.com/recordings/meeting.mp3", "https://example.com/transcripts/notes.pdf", ], ) ``` PDFs and images are auto-categorized by `Task.get_files()` / `get_images()` for Agno. Other file types (CSV, JSON, TXT, …) are inlined into the message via `Task.to_message()`. #### Structured output ```python theme={"dark"} from xpander_sdk import OutputFormat task = await backend.ainvoke_agent( agent_id="agent-123", prompt="Extract company name and revenue from the press release.", file_urls=["https://example.com/press-release.pdf"], output_format=OutputFormat.Json, output_schema={ "type": "object", "properties": { "company": {"type": "string"}, "revenue_usd": {"type": "number"}, }, "required": ["company"], }, ) ``` #### Stream events ```python theme={"dark"} task = await backend.ainvoke_agent( agent_id="agent-123", prompt="Long-running research task", events_streaming=True, ) async for event in task.aevents(): print(event.type, event.data) ``` #### Continue an existing task ```python theme={"dark"} task = await backend.ainvoke_agent( agent_id="agent-123", existing_task_id="task_abc123", prompt="Now summarize what you found.", ) ``` `existing_task_id` reuses the same memory thread, so the agent has full context from the prior run. #### Per-end-user context ```python theme={"dark"} from xpander_sdk import User task = await backend.ainvoke_agent( agent_id="agent-123", prompt="What's on my calendar this afternoon?", user_details=User( id="user_42", email="alex@example.com", first_name="Alex", timezone="America/New_York", ), ) ``` The `User` object scopes user-memory storage and connector authentication (e.g. OAuth tokens for Gmail or Calendar) to the right end user. ### Sync version ```python theme={"dark"} task = backend.invoke_agent( agent_id="agent-123", prompt="Hello!", ) ``` Identical signature; blocks until the task is created. Don't call from inside a running event loop: use `ainvoke_agent` there. ## report\_external\_task `Backend.areport_external_task` logs a task that was executed outside the xpander.ai runtime (for example, in a queue worker, a Lambda, or a different process) so it shows up in the same task history, metrics, and observability views as platform-managed tasks. Use this when you've called an LLM yourself (outside of an `@on_task` handler) but still want the run to count toward agent metrics and appear in the dashboard. ```python theme={"dark"} from xpander_sdk import Backend, Tokens backend = Backend() reported = await backend.areport_external_task( agent_id="agent-123", id="ext-job-9921", input="Summarize Q4 earnings", result="Q4 revenue grew 22% YoY, driven by ...", tokens=Tokens(prompt_tokens=2_140, completion_tokens=380), duration=4.7, used_tools=["web_search", "fetch_pdf"], is_success=True, ) print(reported.id, reported.status) ``` #### Parameters | Parameter | Type | Required | Default | Description | | --------------- | --------------- | -------- | -------------------------- | ---------------------------------------------------------------------------------- | | `agent_id` | `str` | No¹ | `XPANDER_AGENT_ID` env var | Agent the run is associated with. Falls back to `agent.id` if `agent` is provided. | | `agent` | `Agent` | No¹ | `None` | Pre-loaded `Agent` instance. Takes precedence over `agent_id`. | | `id` | `str` | No | `None` | External task identifier. Re-using the same ID updates the existing record. | | `input` | `str` | No | `None` | Input prompt for the run. | | `llm_response` | `Any` | No | `None` | The raw LLM response object (provider-specific). Stored verbatim for debugging. | | `tokens` | `Tokens` | No | `None` | Token usage. Used by metrics. | | `is_success` | `bool` | No | `True` | Whether the run completed successfully. Sets task status accordingly. | | `result` | `str` | No | `None` | Final result string. | | `duration` | `float` | No | `0` | Wall-clock duration in seconds. | | `used_tools` | `list[str]` | No | `None` | Names of tools the run called. | | `configuration` | `Configuration` | No | Module's config | Override SDK configuration for this call. | ¹ Either `agent_id` or `agent` must resolve. The method also reads `XPANDER_AGENT_ID` as a final fallback. #### Returns `Task` The platform-side `Task` record after persistence. Re-using `id` returns the updated record; new `id`s create a fresh task. ### Examples #### Idempotent updates Pass the same `id` to update an in-progress task as it makes progress: ```python theme={"dark"} # Mark started await backend.areport_external_task( agent_id="agent-123", id="job-7842", input="Long-running data extraction", is_success=True, result=None, duration=0, ) # ... do the work ... # Mark completed with final tokens await backend.areport_external_task( agent_id="agent-123", id="job-7842", input="Long-running data extraction", result="Extracted 412 rows", tokens=Tokens(prompt_tokens=18_400, completion_tokens=2_100), duration=37.6, is_success=True, used_tools=["s3_read", "snowflake_query"], ) ``` #### Using a pre-loaded agent ```python theme={"dark"} agent = await agents.aget("agent-123") await backend.areport_external_task( agent=agent, id="ext-2025-04-25-001", input="Daily summary", result="...", is_success=True, ) ``` #### Reporting a failure ```python theme={"dark"} try: result = run_llm_locally(prompt) except Exception as e: await backend.areport_external_task( agent_id="agent-123", id="job-failed-001", input=prompt, result=str(e), is_success=False, ) raise ``` `is_success=False` marks the task as failed in the dashboard. ### Sync version ```python theme={"dark"} backend.report_external_task( agent_id="agent-123", id="ext-001", input="...", result="...", ) ``` Same signature; blocks until the report is persisted. # Decorators Source: https://docs.xpander.ai/developers/sdk-reference/decorators Wire your code into the agent runtime (task handlers, lifecycle, and tool hooks). Decorators are how your Python module becomes a deployed agent worker. The platform dispatches incoming task events to your `@on_task` handler over SSE, calls `@on_boot` once at startup, runs `@on_tool_*` hooks around every tool invocation, and routes auth events through `@on_auth_event`. | Decorator | Purpose | | ----------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------- | | [`@on_task`](/developers/sdk-reference/decorators#@on_task) | Handle incoming tasks. The primary entry point for any SDK-based agent. | | [`@on_boot`](/developers/sdk-reference/decorators#@on_boot-/-@on_shutdown) | Run once at startup, before the SSE listener subscribes. | | [`@on_shutdown`](/developers/sdk-reference/decorators#@on_boot-/-@on_shutdown) | Run once during graceful shutdown. | | [`@on_auth_event`](/developers/sdk-reference/decorators#@on_auth_event) | Receive MCP/OAuth authentication events as they happen. | | [`@on_tool_before`](/developers/sdk-reference/decorators#@on_tool_before-/-@on_tool_after-/-@on_tool_error) | Run before any tool invocation. | | [`@on_tool_after`](/developers/sdk-reference/decorators#@on_tool_before-/-@on_tool_after-/-@on_tool_error) | Run after a successful tool invocation. | | [`@on_tool_error`](/developers/sdk-reference/decorators#@on_tool_before-/-@on_tool_after-/-@on_tool_error) | Run when a tool invocation raises. | For the tool-registration decorator, see [`@register_tool`](/developers/sdk-reference/tools#register_tool-classmethod): it lives next to the tools API, since it constructs `Tool` objects rather than wiring runtime hooks. ## Minimal worker ```python theme={"dark"} from xpander_sdk import Backend, on_task, on_boot, on_shutdown from xpander_sdk.modules.tasks.sub_modules.task import Task from agno.agent import Agent as AgnoAgent backend = Backend() @on_boot async def boot(): print("Worker starting…") @on_shutdown async def shutdown(): print("Worker stopping…") @on_task async def handler(task: Task) -> Task: args = await backend.aget_args( agent_id=task.agent_id, agent_version=task.agent_version, task=task, ) agno_agent = AgnoAgent(**args) result = await agno_agent.arun(input=task.to_message()) task.result = result.content return task ``` Run this module: `python worker.py`: and the worker subscribes to the platform's SSE stream, picks up tasks dispatched to its agent, runs them, and saves results. Tasks are auto-marked `Completed` (or `Error` on raise) and metrics are reported automatically when `task.tokens` is set. ## Required environment `@on_task` validates required env vars eagerly at import. Missing any of these raises `ModuleException`: | Variable | Required for | | ------------------------- | -------------------- | | `XPANDER_API_KEY` | Authentication. | | `XPANDER_ORGANIZATION_ID` | Routing. | | `XPANDER_AGENT_ID` | Worker registration. | For local development without an org-managed agent, set these to your dev values. ## @on\_task `@on_task` registers a function as the agent's task executor. The decorated function runs every time the platform dispatches a task to this worker: over SSE in production, and via the embedded HTTP server (`POST /invoke` on port 59321) for local invocations and Cloud Run-style integrations. The runtime auto-detects whether your function is a regular handler (returns `Task`) or a streaming handler (async generator that yields `TaskUpdateEvent`). ```python theme={"dark"} from xpander_sdk import Backend, on_task from xpander_sdk.modules.tasks.sub_modules.task import Task from agno.agent import Agent as AgnoAgent backend = Backend() @on_task async def handler(task: Task) -> Task: args = await backend.aget_args( agent_id=task.agent_id, agent_version=task.agent_version, task=task, ) agno_agent = AgnoAgent(**args) result = await agno_agent.arun(input=task.to_message()) task.result = result.content return task ``` ### Decorator forms ```python theme={"dark"} @on_task def fn(task: Task) -> Task: ... @on_task(configuration=config) def fn(task: Task) -> Task: ... @on_task(test_task=local_test_task) async def fn(task: Task) -> Task: ... ``` | Parameter | Type | Default | Description | | --------------- | --------------- | ------- | ----------------------------------------------------------------------------------------------------------------------------------------- | | `configuration` | `Configuration` | `None` | SDK config for the underlying `Events` module. Falls back to env vars. | | `test_task` | `LocalTaskTest` | `None` | A simulated task to run locally. The runtime invokes the handler once with this task and exits, instead of subscribing to the SSE stream. | #### Required signature The handler must accept exactly one parameter named `task`. Either positional or keyword form works. ```python theme={"dark"} @on_task def handler(task: Task) -> Task: # ✓ ... @on_task async def handler(task: Task) -> Task: # ✓ ... @on_task async def handler(thing: Task): # ✗ raises TypeError: must be named `task` ... ``` ### Handler types The decorator detects which kind you wrote by inspecting whether your function is an async generator. #### Regular handler Sync or async, returns the (possibly mutated) `Task`. ```python theme={"dark"} @on_task async def handler(task: Task) -> Task: task.result = "done" return task ``` The runtime persists the returned task automatically. Don't call `task.asave()` yourself unless you need to checkpoint mid-handler. #### Streaming handler Async generator that yields `TaskUpdateEvent`s. Used for token-by-token streaming responses. A streaming handler emits two kinds of events. Each token (or text chunk) from the LLM is yielded as a `TaskUpdateEventType.Chunk` event, which the platform forwards to subscribers in real time. After the loop ends, the handler yields one final `TaskUpdateEventType.TaskFinished` event carrying the completed `Task` object. The platform uses that final event to mark the task complete and persist its result. ```python theme={"dark"} from datetime import datetime, timezone from xpander_sdk import on_task, TaskUpdateEvent, TaskUpdateEventType @on_task async def handler(task: Task): async for chunk in stream_from_llm(task.to_message()): yield TaskUpdateEvent( type=TaskUpdateEventType.Chunk, task_id=task.id, organization_id=task.organization_id, time=datetime.now(timezone.utc), data=chunk, ) yield TaskUpdateEvent( type=TaskUpdateEventType.TaskFinished, task_id=task.id, organization_id=task.organization_id, time=datetime.now(timezone.utc), data=task, # final Task object ) ``` Streaming handlers are exposed via `POST /invoke` only: the SSE listener wraps them in an adapter that consumes the generator and tracks the final `Task` from the `TaskFinished` event. ### What the runtime does When you decorate a function with `@on_task`: 1. **Validates the signature** (must accept `task`). 2. **Detects handler type** (regular vs streaming). 3. **Starts an embedded HTTP server** on port `59321` for `POST /invoke` (always, in a daemon thread). Override the port with `XPANDER_STREAMING_PORT`. 4. **Registers an SSE listener** with the `Events` module. The listener: * Reads `XPANDER_API_KEY`, `XPANDER_ORGANIZATION_ID`, `XPANDER_AGENT_ID` from env (raises `ModuleException` if any are missing). * Subscribes to the platform's task-dispatch stream. * Acquires a semaphore (`max_sync_workers=6` by default) before dispatching. * Sets task status to `Executing` before calling your handler. * Calls your handler. * Persists the returned task; if your handler raised, marks the task `Error` with the exception string as the result. * Reports metrics if `task.tokens` is set. * Re-runs the handler with a continuation prompt if [deep planning](/developers/sdk-reference/tasks#state) is enabled (multi-step task plans tracked in `task.deep_planning`) and items remain incomplete, up to `MAX_PLAN_RETRIES = 5`. Pre-retry the runtime triggers session compaction. ### Test mode Pass `test_task` (or use the CLI override) to invoke the handler once locally instead of subscribing to the platform. #### With a `LocalTaskTest` ```python theme={"dark"} from xpander_sdk import on_task from xpander_sdk.modules.tasks.models.task import LocalTaskTest, AgentExecutionInput from xpander_sdk.models.shared import OutputFormat local_test_task = LocalTaskTest( input=AgentExecutionInput(text="What can you do?"), output_format=OutputFormat.Json, output_schema={"capabilities": "list of capabilities"}, ) @on_task(test_task=local_test_task) async def handler(task: Task) -> Task: task.result = {"capabilities": ["Search", "Summarize"]} return task ``` The runtime registers a worker, creates the test task, dispatches it to the handler, and exits after completion (printing the final result). Useful for local iteration without invoking from the dashboard. #### From the CLI The decorator also responds to `--invoke` / `--prompt` arguments on `sys.argv`, so you can run any `@on_task`-decorated module with: ```bash theme={"dark"} python worker.py --invoke --prompt "Try this prompt" --output_format json ``` Supported flags: | Flag | Purpose | | ----------------- | ----------------------------------------------------------- | | `--invoke` | Switches the runtime into single-task test mode. | | `--prompt` | Required when `--invoke` is set. Becomes `task.input.text`. | | `--output_format` | One of `json`, `markdown`, `text`. | | `--output_schema` | JSON-encoded schema string. | ### Runtime caveats * **One handler per process.** The decorator subscribes to the SSE stream on import. Decorating multiple functions in the same module isn't useful: the most recently registered handler wins. Use multiple Python processes if you need to host different agents. * **HTTP server starts immediately.** The `POST /invoke` endpoint is up before the SSE listener finishes connecting. If port `59321` is in use the runtime logs a warning and continues. Override the port with the `XPANDER_STREAMING_PORT` env var. * **Synchronous handlers are dispatched on a thread pool.** A thread pool of `max_sync_workers=6` handles sync handlers concurrently. Async handlers run on the event loop. ### Errors raised by the decorator * `TypeError`: handler doesn't accept `task`, or returns/yields the wrong type. * `ModuleException`: required env vars are missing when the SSE listener starts. ## @on\_boot / @on\_shutdown `@on_boot` registers a function to run **before** the SSE listener subscribes to the platform: useful for warming caches, opening database pools, validating environment, or pre-fetching data. `@on_shutdown` registers a function to run during graceful shutdown. ```python theme={"dark"} from xpander_sdk import on_boot, on_shutdown @on_boot async def warm_caches(): print("Boot: warming caches…") await prefetch_models() @on_shutdown async def cleanup(): print("Shutting down…") await close_connections() ``` Both decorators accept either sync or async functions, and you can register multiple handlers: the runtime invokes them in registration order. ### Decorator forms ```python theme={"dark"} @on_boot def fn(): ... @on_boot(configuration=config) async def fn(): ... ``` ```python theme={"dark"} @on_shutdown def fn(): ... @on_shutdown(configuration=config) async def fn(): ... ``` | Parameter | Type | Default | Description | | --------------- | --------------- | ------- | ---------------------------------------------------------------------------------------------------------------------- | | `configuration` | `Configuration` | `None` | Reserved for future use. Currently only the `Events` module reads config; boot/shutdown handlers receive no arguments. | ### Lifecycle ordering ```text theme={"dark"} Process start ↓ @on_boot handlers (in registration order, await one at a time) ↓ Events.start(): subscribes to SSE, begins task dispatch ↓ … task dispatch ongoing … ↓ SIGINT / SIGTERM received ↓ Events.stop(): cancels tracked tasks, closes thread pool ↓ @on_shutdown handlers (in registration order, errors logged but don't block) ↓ Process exit ``` If a `@on_boot` handler raises, the worker fails to start: the exception propagates and the process exits. If a `@on_shutdown` handler raises, the error is logged but the runtime continues with the next shutdown handler. ### Examples #### Open a DB pool at boot, close on shutdown ```python theme={"dark"} import asyncpg from xpander_sdk import on_boot, on_shutdown pool = None @on_boot async def open_pool(): global pool pool = await asyncpg.create_pool(dsn="postgresql://…") @on_shutdown async def close_pool(): if pool: await pool.close() ``` #### Validate env at boot ```python theme={"dark"} import os from xpander_sdk import on_boot @on_boot def check_env(): for var in ("OPENAI_API_KEY", "REDIS_URL"): if not os.environ.get(var): raise RuntimeError(f"Missing required env var: {var}") ``` Raising in `@on_boot` aborts startup before the worker takes any tasks: useful for fail-fast environment validation. #### Multiple handlers ```python theme={"dark"} @on_boot def first(): print("1") @on_boot def second(): print("2") ``` Both run, in declaration order: `1` then `2`. The runtime awaits each one before moving on. #### Sync and async mix ```python theme={"dark"} @on_boot def synchronous(): print("sync boot") @on_boot async def asynchronous(): print("async boot") await asyncio.sleep(0) ``` Sync handlers are called directly; async ones are awaited. Either works. ### Notes * Boot/shutdown handlers are class-level on `Events`. They register globally per process: there's no scoping to a specific `Events` instance. This is fine for a one-process-one-agent model. * Shutdown handlers run after the SSE listener is stopped but before final cleanup. By then the process is no longer accepting new tasks; in-flight tasks are cancelled. ## @on\_tool\_before / @on\_tool\_after / @on\_tool\_error `@on_tool_before`, `@on_tool_after`, and `@on_tool_error` register hooks that fire around tool invocations: useful for logging, validation, caching, alerting, or analytics. The hooks run during every `Tool.ainvoke` (which means around every framework-driven tool call too). ```python theme={"dark"} from xpander_sdk import on_tool_before, on_tool_after, on_tool_error @on_tool_before async def log_invoke(tool, payload, payload_extension, tool_call_id, agent_version): print(f"→ {tool.name} {payload}") @on_tool_after async def log_success(tool, payload, payload_extension, tool_call_id, agent_version, result): print(f"✓ {tool.name} → {result}") @on_tool_error async def log_error(tool, payload, payload_extension, tool_call_id, agent_version, error): print(f"✗ {tool.name} failed: {error}") ``` You can register multiple hooks of each type: they fire in registration order. Sync and async functions are both supported. ### Required signatures | Decorator | Parameters | Notes | | ----------------- | --------------------------------------------------------------------------------- | --------------------------------------------------------------------- | | `@on_tool_before` | `tool`, `payload`, `payload_extension`, `tool_call_id`, `agent_version` | Fires before the tool runs. | | `@on_tool_after` | `tool`, `payload`, `payload_extension`, `tool_call_id`, `agent_version`, `result` | Fires after a successful invocation. `result` is the tool's response. | | `@on_tool_error` | `tool`, `payload`, `payload_extension`, `tool_call_id`, `agent_version`, `error` | Fires when the invocation raises. `error` is the exception. | | Parameter | Type | Description | | ----------------------- | -------------- | ------------------------------------------------------- | | `tool` | `Tool` | The tool being invoked. | | `payload` | `Any` | The input payload after schema validation. | | `payload_extension` | `dict \| None` | Extra fields that will be deep-merged into the payload. | | `tool_call_id` | `str \| None` | Correlation id matching the LLM tool-call. | | `agent_version` | `str \| None` | Agent version pinned for the call. | | `result` *(after only)* | `Any` | The tool's response. | | `error` *(error only)* | `Exception` | The raised exception. | ### Decorator forms ```python theme={"dark"} @on_tool_before def fn(...): ... @on_tool_before(configuration=config) def fn(...): ... ``` The same form applies to `@on_tool_after` and `@on_tool_error`. The optional `configuration` parameter is reserved for future use; hooks don't currently read it. ### Examples #### Log every tool call ```python theme={"dark"} import time import contextvars start_time = contextvars.ContextVar("start_time") @on_tool_before def begin(tool, payload, *_): start_time.set(time.perf_counter()) print(f"[{tool.name}] start") @on_tool_after def done(tool, payload, *_, result=None): elapsed = time.perf_counter() - start_time.get() print(f"[{tool.name}] done in {elapsed*1000:.0f}ms") @on_tool_error def failed(tool, payload, *_, error=None): elapsed = time.perf_counter() - start_time.get() print(f"[{tool.name}] failed in {elapsed*1000:.0f}ms: {error}") ``` #### Block invocations matching a payload pattern Hooks can't cancel invocations directly (the runtime catches their exceptions and continues), but you can mutate state or short-circuit by raising a guard before the call: ```python theme={"dark"} @on_tool_before def block_test_payloads(tool, payload, *_): if isinstance(payload, dict) and payload.get("test_mode"): raise RuntimeError("test_mode payloads are blocked") ``` Hooks that raise are caught by the runtime: the exception is logged but doesn't propagate to the caller. To genuinely block a tool, validate at the framework layer or in `@register_tool` function bodies. #### Cache successful results ```python theme={"dark"} cache: dict = {} @on_tool_after def cache_result(tool, payload, _ext, _id, _ver, result): if hasattr(payload, "items"): key = (tool.id, frozenset(payload.items())) cache[key] = result ``` #### Alert on failures ```python theme={"dark"} @on_tool_error async def alert(tool, payload, _ext, _id, _ver, error): await pagerduty.fire(f"tool {tool.id} failed: {error}") ``` ### Notes * Hooks fire **once per tool invocation**, regardless of whether the tool is local or remote. * Exceptions in hooks are caught and logged via `loguru`: they never crash the invocation pipeline. * Hooks are class-level on `ToolHooksRegistry` (process-wide singleton). There's no scoping to a specific repository. * The auto-emitted `ToolCallRequest` / `ToolCallResult` events on `task.aevents()` are independent of these hooks. The hooks fire even when `report_activity=False` in `Tool.ainvoke`. ## @on\_auth\_event `@on_auth_event` registers a handler that fires whenever the agent runtime emits an authentication event: for example, when an MCP server requires the end-user to log in via OAuth. Use it to surface the OAuth URL to your UI, kick off external auth flows, or log auth attempts. ```python theme={"dark"} from xpander_sdk import on_auth_event from xpander_sdk.modules.agents.sub_modules.agent import Agent from xpander_sdk.modules.tasks.sub_modules.task import Task, TaskUpdateEvent @on_auth_event async def handle_auth(agent: Agent, task: Task, event: TaskUpdateEvent): print(f"Auth required for {agent.name}") print(f"Task: {task.id}") print(f"Auth data: {event.data}") ``` The handler is auto-registered globally: you don't pass it anywhere. Every `Backend.aget_args(...)` call routes auth events through registered handlers automatically. ### Required signature The function must accept exactly three parameters: `agent`, `task`, `event`. Names are flexible; arity matters. Sync or async are both accepted. ```python theme={"dark"} @on_auth_event async def handler(agent, task, event): # ✓ ... @on_auth_event def handler(agent, task, event): # ✓ (sync) ... @on_auth_event def handler(agent, task): # ✗ TypeError: needs 3 params ... ``` | Parameter | Type | Description | | --------- | ----------------- | ------------------------------------------------------------------ | | `agent` | `Agent` | The agent processing the task. | | `task` | `Task` | The current task. | | `event` | `TaskUpdateEvent` | `event.type == "auth_event"`. `event.data` holds the auth payload. | `event.type` is always `"auth_event"` for handlers registered with this decorator. ### Event payload shapes `event.data` is one of the MCP OAuth response variants. Switch on `event.data.type`: | `type` | `event.data.data` | | ---------------------------------------------------------- | --------------------------------------------------------------------- | | `MCPOAuthResponseType.LOGIN_REQUIRED` (`"login_required"`) | `MCPOAuthGetTokenLoginRequiredResponse(url, server_url, server_name)` | | `MCPOAuthResponseType.TOKEN_READY` (`"token_ready"`) | `MCPOAuthGetTokenTokenReadyResponse(access_token)` | | `MCPOAuthResponseType.TOKEN_ISSUE` (`"token_issue"`) | `MCPOAuthGetTokenGenericResponse(message)` | | `MCPOAuthResponseType.NOT_SUPPORTED` (`"not_supported"`) | `MCPOAuthGetTokenGenericResponse(message)` | ### Examples #### Show the OAuth URL to the user ```python theme={"dark"} @on_auth_event async def show_oauth_url(agent, task, event): payload = event.data if payload.type == "login_required": login = payload.data await my_ui.show(f"Please authenticate with {login.server_name}: {login.url}") ``` #### Multiple handlers stack ```python theme={"dark"} @on_auth_event async def log_auth(agent, task, event): audit_log.info(f"auth event for {agent.id}: {event.data}") @on_auth_event async def notify_user(agent, task, event): await pubsub.publish(f"user:{task.input.user.id}", event.data) ``` Both handlers fire on every auth event. Order is registration order. #### Combine with a per-call callback You can pass an additional one-off callback to `Backend.aget_args(auth_events_callback=...)`: it runs *in addition to* every globally-registered handler. ```python theme={"dark"} @on_auth_event async def global_handler(agent, task, event): audit(event) # Per-call extra: async def per_call(agent, task, event): await my_ui.show_special_state(event) args = await backend.aget_args( agent_id="agent-123", auth_events_callback=per_call, ) ``` Both `global_handler` and `per_call` fire when an auth event happens during the resulting agent's run. ### Helper functions The module also exposes two helpers for testing and management: ```python theme={"dark"} from xpander_sdk.modules.backend.decorators.on_auth_event import ( get_registered_handlers, clear_handlers, ) # Inspect what's registered handlers = get_registered_handlers() # Wipe registered handlers (useful between tests) clear_handlers() ``` These aren't re-exported from the top-level `xpander_sdk` package: import from the decorator module directly. # Knowledge Bases Source: https://docs.xpander.ai/developers/sdk-reference/knowledge-bases Create and manage RAG-style knowledge bases programmatically. The `KnowledgeBases` module is the entry point for managing knowledge bases: vector stores backed by uploaded documents. Use it to list existing KBs, load one, or create a new KB. The actual document operations (`add_documents`, `search`, `list_documents`, `delete`) live on the `KnowledgeBase` instance. ```python theme={"dark"} from xpander_sdk import KnowledgeBases kbs = KnowledgeBases() # Create kb = await kbs.acreate(name="Q4 Reports", description="Quarterly earnings") # Add documents await kb.aadd_documents([ "https://example.com/Q4-2024.pdf", "https://example.com/Q4-2025.pdf", ]) # Search results = await kb.asearch(search_query="revenue trends", top_k=5) for r in results: print(r.score, r.content[:80]) ``` ## Constructor ```python theme={"dark"} KnowledgeBases(configuration: Optional[Configuration] = None) ``` | Parameter | Type | Default | Description | | --------------- | --------------- | ------- | ------------------------------------------ | | `configuration` | `Configuration` | `None` | SDK configuration. Falls back to env vars. | ## Module methods | Method | Returns | What it does | | ------------------------------------------------------------------------ | --------------------- | ------------------------------ | | [`alist` / `list`](/developers/sdk-reference/knowledge-bases#list) | `list[KnowledgeBase]` | All KBs accessible to the org. | | [`aget` / `get`](/developers/sdk-reference/knowledge-bases#get) | `KnowledgeBase` | Load one KB by id. | | [`acreate` / `create`](/developers/sdk-reference/knowledge-bases#create) | `KnowledgeBase` | Create a new KB. | ## `KnowledgeBase` instance methods See the [`KnowledgeBase` class reference](/developers/sdk-reference/knowledge-bases#knowledgebase-class) for: * `aadd_documents` / `add_documents` * `alist_documents` / `list_documents` * `adelete_multiple_documents` / `delete_multiple_documents` * `asearch` / `search` * `adelete` / `delete` ## Linking to an agent Knowledge bases linked to an agent are configured in the Workbench or with `agent.attach_knowledge_base(...)`. Once linked, the agent's framework retriever queries them automatically: see the [Agent knowledge bases page](/developers/sdk-reference/agents#knowledge-bases). ## create `KnowledgeBases.acreate` provisions a new managed knowledge base. The returned `KnowledgeBase` is empty until you `aadd_documents(...)` to populate it. ```python theme={"dark"} from xpander_sdk import KnowledgeBases kb = await KnowledgeBases().acreate( name="Q4 Reports", description="Quarterly earnings", ) print(kb.id, kb.total_documents) # kb-…, 0 ``` #### Parameters | Parameter | Type | Required | Default | Description | | ------------- | ----- | -------- | ------- | ----------------------------------- | | `name` | `str` | Yes | – | Display name. | | `description` | `str` | No | `""` | Description. Useful for cataloging. | #### Returns `KnowledgeBase` A new `KnowledgeBase` with `total_documents=0`. Use `kb.aadd_documents([...])` to populate it. ### Examples #### Create + populate ```python theme={"dark"} kbs = KnowledgeBases() kb = await kbs.acreate( name="Engineering RFCs", description="All historical RFC documents.", ) await kb.aadd_documents([ "https://docs.acme.com/rfc/0001-architecture.md", "https://docs.acme.com/rfc/0002-deployment.md", ]) ``` `aadd_documents` accepts a list of URLs the platform fetches and ingests. See the [`KnowledgeBase` reference](/developers/sdk-reference/knowledge-bases#aadd_documents-/-add_documents). #### Sync version ```python theme={"dark"} kb = KnowledgeBases().create(name="My KB", description="...") ``` ### Errors Raises [`ModuleException`](/developers/sdk-reference/overview#error-handling) on failure. ## get `KnowledgeBases.aget` loads one knowledge base by id, returning a full `KnowledgeBase` instance. ```python theme={"dark"} from xpander_sdk import KnowledgeBases kb = await KnowledgeBases().aget(knowledge_base_id="kb-456") print(kb.name, kb.total_documents) ``` #### Parameters | Parameter | Type | Required | Description | | ------------------- | ----- | -------- | ----------- | | `knowledge_base_id` | `str` | Yes | KB id. | #### Returns `KnowledgeBase` A full `KnowledgeBase` instance. See the [`KnowledgeBase` class reference](/developers/sdk-reference/knowledge-bases#knowledgebase-class). ### Sync version ```python theme={"dark"} kb = KnowledgeBases().get(knowledge_base_id="kb-456") ``` ### Errors Raises [`ModuleException`](/developers/sdk-reference/overview#error-handling) on failure: | Status | Cause | | ------ | ------------------------------- | | 404 | KB doesn't exist or wrong org. | | 403 | KB exists but isn't accessible. | | 500 | Server error. | ## list `KnowledgeBases.alist` returns every knowledge base your organization owns. ```python theme={"dark"} from xpander_sdk import KnowledgeBases kbs = await KnowledgeBases().alist() for kb in kbs: print(kb.id, kb.name, kb.total_documents) ``` #### Parameters None. #### Returns `list[KnowledgeBase]` Each `KnowledgeBase` is a full instance. See the [`KnowledgeBase` class reference](/developers/sdk-reference/knowledge-bases#knowledgebase-class) for fields and methods. | Field | Type | Description | | ----------------- | ------------------- | --------------------------------------------------------------------- | | `id` | `str` | Knowledge-base identifier. | | `name` | `str` | Display name. | | `description` | `str \| None` | Description. | | `type` | `KnowledgeBaseType` | `MANAGED` (xpander.ai vector store) or `EXTERNAL` (provider-managed). | | `organization_id` | `str` | Owning org. | | `total_documents` | `int` | Document count. | ### Sync version ```python theme={"dark"} kbs = KnowledgeBases().list() ``` ### Errors Raises [`ModuleException`](/developers/sdk-reference/overview#error-handling) on failure. ## KnowledgeBase class `KnowledgeBase` is the instance you get back from `KnowledgeBases.aget`, `acreate`, or `alist`. It carries the KB metadata and the methods to populate, query, and tear it down. ```python theme={"dark"} from xpander_sdk import KnowledgeBases kb = await KnowledgeBases().aget("kb-456") print(kb.id, kb.name, kb.total_documents) ``` ### Attributes | Field | Type | Description | | ----------------- | ----------------------- | -------------------------------------------------- | | `id` | `str` | KB identifier. | | `name` | `str` | Display name. | | `description` | `str \| None` | Description. | | `type` | `KnowledgeBaseType` | `MANAGED` (xpander.ai vector store) or `EXTERNAL`. | | `organization_id` | `str` | Owning org. | | `total_documents` | `int` | Document count. | | `configuration` | `Configuration \| None` | SDK config (carried from the loader). | ### Methods #### `aadd_documents` / `add_documents` Upload documents by URL. The platform fetches the URLs, chunks the content, embeds it, and indexes the embeddings. ```python theme={"dark"} docs = await kb.aadd_documents([ "https://example.com/policy.pdf", "https://example.com/handbook.md", ]) for d in docs: print(d.id, d.document_url) ``` | Parameter | Type | Required | Default | Description | | --------------- | ----------- | -------- | ------- | ---------------------------------------------------------------------------- | | `document_urls` | `list[str]` | Yes | – | URLs to ingest. | | `sync` | `bool` | No | `False` | When `True`, the platform synchronously waits for indexing before returning. | Returns `list[KnowledgeBaseDocumentItem]`: one entry per uploaded document with the platform-assigned `id` and the `document_url`. #### `alist_documents` / `list_documents` List all documents in the KB. ```python theme={"dark"} docs = await kb.alist_documents() ``` Returns `list[KnowledgeBaseDocumentItem]`. `KnowledgeBaseDocumentItem` fields: | Field | Type | Description | | -------------- | ------------- | --------------------------------------------- | | `kb_id` | `str \| None` | Owning KB id. | | `id` | `str \| None` | Document id. | | `document_url` | `str` | URL the platform ingested. | | `raw_data` | `str \| None` | Inline raw text, if it was uploaded directly. | #### `adelete_multiple_documents` / `delete_multiple_documents` Delete documents by id. ```python theme={"dark"} await kb.adelete_multiple_documents(document_ids=["doc-123", "doc-456"]) ``` | Parameter | Type | Required | Description | | -------------- | ----------- | -------- | ----------------------- | | `document_ids` | `list[str]` | Yes | Document ids to delete. | To delete a single document, you can also call `await doc.delete()` on a `KnowledgeBaseDocumentItem` returned by `alist_documents`. #### `asearch` / `search` Semantic search over the KB. Returns top-K matches by score. ```python theme={"dark"} results = await kb.asearch( search_query="how do we handle PII?", top_k=5, ) for r in results: print(f"{r.score:.1f} {r.content[:100]}") ``` | Parameter | Type | Required | Default | Description | | -------------- | ------ | -------- | ------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `search_query` | `str` | Yes | – | Natural-language query. | | `use_bubble` | `bool` | No | `False` | When `False`, each result is just the matched chunk (the indexed text segment). When `True`, the SDK widens each result with surrounding text from the source document (a "bubble" of context) for richer snippets. | | `bubble_size` | `int` | No | `1000` | Width of the surrounding bubble in characters when `use_bubble=True`. | | `top_k` | `int` | No | `10` | Max number of results. | Returns `list[KnowledgeBaseSearchResult]`: | Field | Type | Description | | --------- | ------- | ----------------------------------------------- | | `content` | `str` | Matching text (with bubble context if enabled). | | `score` | `float` | Relevance score, 0–100. | #### `adelete` / `delete` Delete the entire knowledge base. ```python theme={"dark"} await kb.adelete() ``` This is irreversible. The KB and all its documents are removed. ### Examples #### Bulk-add and verify ```python theme={"dark"} docs = await kb.aadd_documents([ f"https://docs.acme.com/handbook/{slug}.md" for slug in ["onboarding", "policies", "engineering"] ]) assert len(docs) == 3 print(f"Added {len(docs)} documents to {kb.name}") ``` #### Search with context ```python theme={"dark"} results = await kb.asearch( search_query="vacation policy", use_bubble=True, bubble_size=2000, top_k=3, ) for r in results: print(f"--- score: {r.score:.1f} ---") print(r.content) ``` `use_bubble=True` is great for human-readable snippets; for embedding into LLM prompts, the default `False` (chunk-only) is usually enough. #### Reindex (delete + re-add) ```python theme={"dark"} docs = await kb.alist_documents() ids = [d.id for d in docs] await kb.adelete_multiple_documents(document_ids=ids) await kb.aadd_documents([d.document_url for d in docs], sync=True) ``` `sync=True` blocks until reindexing finishes, so the KB is queryable when the call returns. ### Errors All KB methods raise [`ModuleException`](/developers/sdk-reference/overview#error-handling) on API failures. # Overview Source: https://docs.xpander.ai/developers/sdk-reference/overview Install the xpander.ai SDK, authenticate, and make your first call. The Python SDK is in **preview**. It's for building in-product agents — agents you write in Python and embed in your own product — and custom agents built on other frameworks (Agno, LangChain, OpenAI Agents, AWS Strands). To invoke or integrate xpander agents from an application, use the [REST API](/api-reference/invoke-api), which is stable and works from any language. The xpander.ai SDK is a typed Python client for the xpander.ai platform. It exposes six core modules (`Backend`, `Agents`, `Tasks`, `ToolsRepository`, `KnowledgeBases`, `Events`), plus a set of decorators (`@on_task`, `@on_boot`, `@on_shutdown`, `@on_auth_event`, `@on_tool_*`, `@register_tool`) for wiring your code into the agent runtime. Every method comes in two flavors: an async coroutine (e.g. `aget`, `acreate_task`) and a synchronous wrapper (`get`, `create_task`). Use the async forms in production; sync wrappers are convenient for scripts and notebooks. ## Install ```bash theme={"dark"} # Requires Python 3.9+ pip install xpander-sdk ``` For Agno (the recommended framework), install the optional extras: ```bash theme={"dark"} pip install xpander-sdk[agno] ``` ## Authenticate The SDK reads credentials from environment variables by default: ```bash theme={"dark"} export XPANDER_API_KEY="your-api-key" export XPANDER_ORGANIZATION_ID="your-org-id" # Optional: export XPANDER_BASE_URL="https://inbound.xpander.ai" # cloud default export XPANDER_AGENT_ID="agent-123" # avoids passing agent_id everywhere ``` Or instantiate `Configuration` explicitly and pass it into any module: ```python theme={"dark"} from xpander_sdk import Configuration, Agents config = Configuration( api_key="your-api-key", organization_id="your-org-id", ) agents = Agents(configuration=config) ``` See the [Configuration reference](/developers/sdk-reference/overview#configuration) for the full attribute list and self-hosted setup. ## Initialize and call ```python theme={"dark"} import asyncio from xpander_sdk import Agents async def main(): agents = Agents() # picks up env vars agent = await agents.aget("agent-123") # load agent config task = await agent.acreate_task( prompt="Summarize the latest sales report", file_urls=["https://example.com/sales.csv"], ) print(task.id, task.status) asyncio.run(main()) ``` For framework integration (Agno, OpenAI Agents, LangChain, Google ADK, AWS Strands), use `Backend.aget_args()` to resolve framework-specific kwargs from a stored agent configuration: ```python theme={"dark"} from xpander_sdk import Backend from agno.agent import Agent as AgnoAgent backend = Backend() args = await backend.aget_args(agent_id="agent-123", task=task) agno_agent = AgnoAgent(**args) result = await agno_agent.arun(input="Hello!") ``` ## Async vs sync Every coroutine has a sync sibling: same parameters, blocks until complete: | Async | Sync | | ----------------------------- | ---------------------------- | | `agents.aget(...)` | `agents.get(...)` | | `agent.acreate_task(...)` | `agent.create_task(...)` | | `task.aevents()` | `task.events()` | | `tools.aload_tool_by_id(...)` | `tools.load_tool_by_id(...)` | Async methods are coroutines: wrap them in `async def` and call with `await`. Sync wrappers internally call `run_sync()`, so don't call them from inside an existing event loop (FastAPI, asyncio scripts): use the `a*` form there. ## Self-hosted Point `base_url` at your Agent Controller endpoint and use the API key generated during your Helm install: ```python theme={"dark"} config = Configuration( api_key="agent-controller-api-key", organization_id="your-org-id", base_url="https://agent-controller.your-company.com", ) ``` The SDK auto-detects when the URL points at a self-hosted controller (`agent-controller` in the host or port `9016`) and prefixes paths with the organization ID. See the [Configuration reference](/developers/sdk-reference/overview#self-hosted) for details. ## Where to next Resolve framework args, invoke agents directly, report external runs. List, load, and interact with agents. Create, stream, and inspect task executions. `@on_task`, `@on_boot`, `@on_shutdown`, and tool hooks. ## Configuration `Configuration` is the credentials object every SDK module accepts. By default each module instantiates its own `Configuration` from environment variables, so most code never touches it directly. Construct one explicitly when you need to override credentials or point at a self-hosted controller. ```python theme={"dark"} from xpander_sdk import Configuration config = Configuration( api_key="your-api-key", organization_id="your-org-id", ) ``` ### Constructor ```python theme={"dark"} Configuration( api_key: Optional[str] = None, # XPANDER_API_KEY base_url: Optional[str] = None, # XPANDER_BASE_URL organization_id: Optional[str] = None, # XPANDER_ORGANIZATION_ID agent_id: Optional[str] = None, # XPANDER_AGENT_ID ) ``` #### Attributes | Attribute | Type | Default | Description | | ----------------- | ------------- | --------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------ | | `api_key` | `str \| None` | `XPANDER_API_KEY` env var | API key for authentication. Required for any cloud call. | | `organization_id` | `str \| None` | `XPANDER_ORGANIZATION_ID` env var | Organization identifier. Required for self-hosted controllers; optional but recommended for cloud. | | `base_url` | `str \| None` | Auto-detected from env | API endpoint. Defaults to `https://inbound.xpander.ai` for cloud. Set to your Agent Controller URL for self-hosted. | | `agent_id` | `str \| None` | `None` | Optional default agent ID. When set, methods that take `agent_id` can be called without arguments. Falls back to `XPANDER_AGENT_ID`. | ### Environment variables The SDK reads these on import. Setting them once via `.env` or your shell removes the need to construct `Configuration` manually. | Variable | Purpose | | ------------------------- | -------------------------------------------------------------------------------------------------- | | `XPANDER_API_KEY` | API key. **Required.** | | `XPANDER_ORGANIZATION_ID` | Organization ID. Required for self-hosted; recommended for cloud. | | `XPANDER_BASE_URL` | Override the API base URL. | | `XPANDER_AGENT_ID` | Default agent ID. Lets `Backend()`, `Events()`, and `Agents().aget()` work without an explicit ID. | ```python theme={"dark"} from dotenv import load_dotenv from xpander_sdk import Configuration load_dotenv() config = Configuration() # picks up XPANDER_* vars ``` ### Methods #### `get_full_url() -> str` Returns the API URL, with the organization ID appended when the controller requires it. ```python theme={"dark"} config = Configuration( base_url="https://agent-controller.acme.com", organization_id="org_123", ) config.get_full_url() # 'https://agent-controller.acme.com/org_123' config = Configuration( base_url="https://inbound.xpander.ai", organization_id="org_123", ) config.get_full_url() # 'https://inbound.xpander.ai' (cloud: no prefix) ``` The org ID is appended automatically when `base_url` contains `agent-controller` or port `9016`. You don't need to do this yourself. ### Self-hosted Use the **Agent Controller API key** generated during your Helm install (not your cloud API key) and point `base_url` at the controller: ```python theme={"dark"} config = Configuration( api_key="agent-controller-api-key", organization_id="your-org-id", base_url="https://agent-controller.your-company.com", ) ``` Or via environment: ```bash theme={"dark"} export XPANDER_API_KEY="agent-controller-api-key" export XPANDER_ORGANIZATION_ID="your-org-id" export XPANDER_BASE_URL="https://agent-controller.your-company.com" ``` The `base_url` must point at the Agent Controller endpoint (e.g. `https://agent-controller.{your-domain}`), not the root domain. The SDK detects this URL pattern and prefixes paths with the organization ID via `get_full_url()`. ### Sharing config across modules Pass the same `Configuration` to every module so they hit the same endpoint and use the same credentials: ```python theme={"dark"} from xpander_sdk import Configuration, Agents, Tasks, KnowledgeBases config = Configuration(api_key="...", organization_id="...") agents = Agents(configuration=config) tasks = Tasks(configuration=config) kbs = KnowledgeBases(configuration=config) ``` Loaded objects (`Agent`, `Task`, `KnowledgeBase`) carry the `Configuration` they were loaded with, so subsequent method calls on them reuse it automatically. ## Types A consolidated reference for every enum and Pydantic model exposed at the top level of `xpander_sdk`. Methods that take or return these types link here. ### Enums #### `OutputFormat` ```python theme={"dark"} from xpander_sdk import OutputFormat ``` | Value | String | Use | | ----------------------- | ------------ | ---------------------------------------------------------- | | `OutputFormat.Text` | `"text"` | Plain text. | | `OutputFormat.Markdown` | `"markdown"` | Markdown-formatted text (default for most agents). | | `OutputFormat.Json` | `"json"` | Structured JSON. Pair with `output_schema` for validation. | | `OutputFormat.Voice` | `"voice"` | MP3 voice output (requires `voice_id` on the agent). | #### `ThinkMode` ```python theme={"dark"} from xpander_sdk.models.shared import ThinkMode ``` | Value | String | Use | | ------------------- | ----------- | -------------------------------------- | | `ThinkMode.Default` | `"default"` | Standard reasoning. | | `ThinkMode.Harder` | `"harder"` | Extended reasoning (uses more tokens). | #### `AgentExecutionStatus` ```python theme={"dark"} from xpander_sdk import AgentExecutionStatus ``` | Value | String | | ----------- | ------------- | | `Pending` | `"pending"` | | `Executing` | `"executing"` | | `Paused` | `"paused"` | | `Error` | `"error"` | | `Failed` | `"failed"` | | `Completed` | `"completed"` | | `Stopped` | `"stopped"` | See the [task lifecycle](/developers/sdk-reference/tasks#lifecycle). #### `AgentDeploymentType` ```python theme={"dark"} from xpander_sdk import AgentDeploymentType ``` | Value | String | | ------------ | -------------- | | `Serverless` | `"serverless"` | #### `AgentStatus` ```python theme={"dark"} from xpander_sdk.modules.agents.models.agent import AgentStatus ``` | Value | String | | ---------- | ------------ | | `DRAFT` | `"DRAFT"` | | `ACTIVE` | `"ACTIVE"` | | `INACTIVE` | `"INACTIVE"` | #### `AgentAccessScope` ```python theme={"dark"} from xpander_sdk.modules.agents.models.agent import AgentAccessScope ``` | Value | String | | ---------------- | ------------------ | | `Personal` | `"personal"` | | `Organizational` | `"organizational"` | #### `AgentType` ```python theme={"dark"} from xpander_sdk.modules.agents.models.agent import AgentType ``` | Value | String | | --------------- | ----------------- | | `Manager` | `"manager"` | | `Regular` | `"regular"` | | `A2A` | `"a2a"` | | `Curl` | `"curl"` | | `Orchestration` | `"orchestration"` | #### `LLMReasoningEffort` ```python theme={"dark"} from xpander_sdk.modules.agents.models.agent import LLMReasoningEffort ``` | Value | String | | -------- | ---------- | | `Low` | `"low"` | | `Medium` | `"medium"` | | `High` | `"high"` | #### `Framework` ```python theme={"dark"} from xpander_sdk.models.frameworks import Framework ``` | Value | String | | -------------- | ------------------ | | `Agno` | `"agno"` | | `LangChain` | `"langchain"` | | `OpenAIAgents` | `"open-ai-agents"` | | `GoogleADK` | `"google-adk"` | | `Strands` | `"strands-agents"` | | `OpenClaw` | `"open-claw"` | Today only Agno is fully wired through `Backend.aget_args`; other values are reserved. #### `MCPServerType`, `MCPServerAuthType`, `MCPServerTransport` See [MCP types](/developers/sdk-reference/tools#mcp-types). #### `TaskUpdateEventType` See [streaming events](/developers/sdk-reference/tasks#events). #### `KnowledgeBaseType` ```python theme={"dark"} from xpander_sdk.modules.knowledge_bases.models.knowledge_bases import KnowledgeBaseType ``` | Value | String | | ---------- | ------------ | | `MANAGED` | `"managed"` | | `EXTERNAL` | `"external"` | ### Models #### `Configuration` See [Configuration](/developers/sdk-reference/overview#configuration). #### `User` ```python theme={"dark"} from xpander_sdk import User User( id: Optional[str] = None, first_name: Optional[str] = None, last_name: Optional[str] = None, email: str, # required additional_attributes: Optional[dict] = None, timezone: Optional[str] = None, # IANA, e.g. "America/New_York" ) ``` End-user context. Pass to `acreate_task(user_details=...)` to scope memory and connector authentication to a specific user. #### `Tokens` ```python theme={"dark"} from xpander_sdk import Tokens Tokens( completion_tokens: int = 0, prompt_tokens: int = 0, ) # tokens.total_tokens is a computed property: completion + prompt ``` Used in `Backend.areport_external_task` and `Task.areport_metrics`. #### `ExecutionTokens` ```python theme={"dark"} from xpander_sdk.models.shared import ExecutionTokens ExecutionTokens( inner: Tokens = Tokens(), # inner orchestration tokens worker: Tokens = Tokens(), # worker LLM tokens ) ``` Used internally for metrics aggregation. #### `AgentInstructions` ```python theme={"dark"} from xpander_sdk.modules.agents.models.agent import AgentInstructions AgentInstructions( role: list[str] = [], goal: list[str] = [], general: str = "", ) ``` Computed properties: `description` (= `general`), `instructions` (formatted XML block), `goal_str`, `full`. #### `AgentExecutionInput` ```python theme={"dark"} from xpander_sdk.modules.tasks.models.task import AgentExecutionInput AgentExecutionInput( text: Optional[str] = "", files: Optional[list[str]] = [], user: Optional[User] = None, ) ``` Stored on `task.input`. Constructed automatically by `acreate_task`. #### `LocalTaskTest` ```python theme={"dark"} from xpander_sdk.modules.tasks.models.task import LocalTaskTest, AgentExecutionInput LocalTaskTest( input: AgentExecutionInput, agent_version: Optional[str] = None, output_format: Optional[OutputFormat] = None, output_schema: Optional[dict] = None, ) ``` Pass to `@on_task(test_task=...)` to invoke the handler once locally instead of subscribing to the platform. #### `TaskUpdateEvent` See [streaming events](/developers/sdk-reference/tasks#events). #### `ToolInvocationResult` See [Tool class: ToolInvocationResult](/developers/sdk-reference/tools#toolinvocationresult). #### `MCPServerDetails` See [MCP types](/developers/sdk-reference/tools#mcp-types). #### `KnowledgeBaseSearchResult` ```python theme={"dark"} from xpander_sdk.modules.knowledge_bases.models.knowledge_bases import KnowledgeBaseSearchResult KnowledgeBaseSearchResult( content: str, score: float, ) ``` Returned by `KnowledgeBase.asearch`. #### `KnowledgeBaseDocumentItem` See the [`KnowledgeBase` reference](/developers/sdk-reference/knowledge-bases#alist_documents-/-list_documents). #### `AgnoSettings` ```python theme={"dark"} from xpander_sdk.models.frameworks import AgnoSettings AgnoSettings( session_storage: bool = True, learning: bool = False, user_memories: bool = False, agentic_memory: bool = False, agent_memories: bool = False, agentic_culture: bool = False, session_summaries: bool = False, num_history_runs: int = 10, max_tool_calls_from_history: int = 0, tool_call_limit: Optional[int] = None, coordinate_mode: bool = False, pii_detection_enabled: bool = False, pii_detection_mask: bool = True, prompt_injection_detection_enabled: bool = False, openai_moderation_enabled: bool = False, openai_moderation_categories: Optional[list[str]] = None, reasoning_tools_enabled: bool = False, ) ``` Per-agent Agno configuration stored on `agent.agno_settings`. Modify in the Workbench; mutating in code only affects the in-memory instance. #### `AgentsListItem` / `TasksListItem` Summary objects returned by `agents.alist()` and `tasks.alist()`. See [`agents.list`](/developers/sdk-reference/agents#list) and [`tasks.list`](/developers/sdk-reference/tasks#list). ### Exceptions #### `ModuleException` ```python theme={"dark"} from xpander_sdk.exceptions.module_exception import ModuleException ``` Raised by every SDK module on API failure. Carries `status_code: int` and `description: str`. See [Error Handling](/developers/sdk-reference/overview#error-handling). ### Constants #### `MAX_PLAN_RETRIES` ```python theme={"dark"} from xpander_sdk import MAX_PLAN_RETRIES # = 5 ``` The maximum number of times the `@on_task` runtime retries a handler when deep-planning tasks remain incomplete after the first run. ### Type aliases #### `LLMModelT` ```python theme={"dark"} from xpander_sdk.models.shared import LLMModelT # = type[ABC] ``` Marker type used internally for typing model classes. ## Error Handling Every SDK module raises `ModuleException` when an API call fails. The exception bundles the HTTP status code with a description so you can branch on the underlying cause. ```python theme={"dark"} from xpander_sdk import Agents from xpander_sdk.exceptions.module_exception import ModuleException agents = Agents() try: agent = await agents.aget("non-existent-agent") except ModuleException as e: print(f"[{e.status_code}] {e.description}") ``` ### `ModuleException` ```python theme={"dark"} from xpander_sdk.exceptions.module_exception import ModuleException ``` | Attribute | Type | Description | | ------------- | ----- | -------------------------------------------------------------------------- | | `status_code` | `int` | HTTP status code from the API response, or `500` for client-side failures. | | `description` | `str` | Human-readable error description (often the raw response body). | The exception's string form is `[{status_code}] {description}`. ### Common status codes | Status | Cause | What to do | | ------ | ---------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------- | | `400` | Malformed request: invalid parameters, missing required fields, schema validation. | Inspect `description`. Fix the call site. | | `401` | Missing or invalid API key. | Verify `XPANDER_API_KEY` / `Configuration.api_key`. For self-hosted, confirm you're using the **Agent Controller** key, not a cloud key. | | `403` | Authenticated but not authorized: wrong organization, agent owned by another user. | Verify `XPANDER_ORGANIZATION_ID`. Check the agent's `access_scope`. | | `404` | Resource doesn't exist: bad agent/task/KB id, or the resource was deleted. | Confirm IDs. Run `agents.list()` / `tasks.list()` to discover what exists. | | `409` | Conflict: duplicate creation, version mismatch on save, or worker environment collision. | Reload the resource (`task.areload()`) and retry. | | `429` | Rate limit. | Back off exponentially. The SDK does not auto-retry on 429. | | `500` | Server error, or any client-side exception (network, parsing, validation). | Inspect `description`. For 500 specifically from the cloud, retry once or twice with backoff. | ### Branching on status ```python theme={"dark"} try: task = await tasks.aget(task_id="task_xyz") except ModuleException as e: if e.status_code == 404: print("Task not found: was it deleted?") elif e.status_code in (401, 403): print("Auth issue: check credentials") else: raise ``` ### Retry strategy The SDK does **not** retry failed requests automatically (except inside `Events.start()`, which retries SSE connections internally). For idempotent operations, wrap calls in your own retry loop: ```python theme={"dark"} import asyncio from xpander_sdk.exceptions.module_exception import ModuleException async def with_retry(coro_fn, *, attempts: int = 3, base_delay: float = 1.0): for attempt in range(1, attempts + 1): try: return await coro_fn() except ModuleException as e: if e.status_code in (429, 500, 502, 503, 504) and attempt < attempts: await asyncio.sleep(base_delay * (2 ** (attempt - 1))) continue raise agent = await with_retry(lambda: agents.aget("agent-123")) ``` Avoid retrying: * `400` / `404`: the request will keep failing. * `acreate` / `acreate_task` without an `existing_task_id`: you may create duplicate resources. Pass `existing_task_id=...` to make creation idempotent. ### Validation errors from `Tool.ainvoke` Tool invocations validate the payload against the tool's auto-generated Pydantic schema before sending the request. A schema mismatch raises `ValueError` (not `ModuleException`): ```python theme={"dark"} try: result = await tool.ainvoke(agent_id="agent-123", payload={"bad": "shape"}) except ValueError as e: print(f"Payload didn't match schema: {e}") ``` Successful invocations still set `is_error=True` on the returned `ToolInvocationResult` if the remote endpoint returned an HTTP error. Check the result, not just exceptions: ```python theme={"dark"} result = await tool.ainvoke(agent_id="agent-123", payload={"city": "NYC"}) if result.is_error: print(f"Tool failed [{result.status_code}]: {result.result}") ``` ### Streaming errors `task.aevents()` raises `ValueError` if the task wasn't created with `events_streaming=True`. The underlying SSE connection logs warnings on parse failures and drops malformed events; it does not raise. Network failures propagate after the SDK's internal retry budget is exhausted (see `Events`). # Tasks Source: https://docs.xpander.ai/developers/sdk-reference/tasks Create, list, update, stop, and stream task executions. The `Tasks` module manages the full lifecycle of task executions: the unit of work an agent does in response to a prompt. List existing tasks, load a specific one, create new ones, patch their state, or terminate them. ```python theme={"dark"} from xpander_sdk import Tasks, AgentExecutionStatus tasks = Tasks() # List items = await tasks.alist(agent_id="agent-123") # Load task = await tasks.aget(task_id="task_xyz") # Create task = await tasks.acreate(agent_id="agent-123", prompt="Hello!") # Update await tasks.aupdate(task_id=task.id, status=AgentExecutionStatus.Completed, result="done") # Stop await tasks.astop(task_id=task.id) ``` ## Constructor ```python theme={"dark"} Tasks(configuration: Optional[Configuration] = None) ``` | Parameter | Type | Default | Description | | --------------- | --------------- | ------- | ------------------------------------------ | | `configuration` | `Configuration` | `None` | SDK configuration. Falls back to env vars. | ## Module methods | Method | Returns | What it does | | ------------------------------------------------------------------------------------------ | --------------------- | ----------------------------------------------------------------------------------- | | [`alist` / `list`](/developers/sdk-reference/tasks#list) | `list[TasksListItem]` | Tasks for a given agent, optionally filtered. | | [`alist_user_tasks` / `list_user_tasks`](/developers/sdk-reference/tasks#tasks-for-a-user) | `list[TasksListItem]` | Tasks for a given end-user across all agents. | | [`aget` / `get`](/developers/sdk-reference/tasks#get) | `Task` | Load a full task by id. | | [`acreate` / `create`](/developers/sdk-reference/tasks#create) | `Task` | Create a new task. (Same as `Agent.acreate_task`, but accepts `agent_id` directly.) | | [`aupdate` / `update`](/developers/sdk-reference/tasks#update) | `Task` | Patch task fields (status, result, payload extension). | | [`astop` / `stop`](/developers/sdk-reference/tasks#stop) | `Task` | Terminate a running task. | ## `Task` instance methods The `Task` object returned by these calls has its own set of methods for runtime control: | Method | What it does | | ---------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------- | | [`asave` / `save`](/developers/sdk-reference/tasks#save) | Persist local mutations back to the platform. | | [`aset_status` / `set_status`](/developers/sdk-reference/tasks#set_status) | Set status (and optionally result) and save in one call. | | [`astop` / `stop`](/developers/sdk-reference/tasks#stop) | Terminate this task. | | [`areload` / `reload`](/developers/sdk-reference/tasks#reload) | Re-fetch the latest task state from the platform. | | [`aevents` / `events`](/developers/sdk-reference/tasks#events) | Stream `TaskUpdateEvent`s via SSE. | | [`aget_activity_log` / `get_activity_log`](/developers/sdk-reference/tasks#get_activity_log) | Full message / tool-call / reasoning thread. | | [`areport_metrics` / `report_metrics`](/developers/sdk-reference/tasks#report_metrics) | Push token counts and other metrics back to the platform. | | [`get_files` / `get_images` / `get_human_readable_files` / `to_message`](/developers/sdk-reference/tasks#agno-helpers) | Convenience helpers for Agno integration. | For the full attribute list, see the [`Task` class reference](/developers/sdk-reference/tasks#task-class). ## Lifecycle ```text theme={"dark"} Pending → Executing → Completed ↓ ↓ Paused Failed ↓ ↓ Error Stopped ``` | Status | Meaning | | ----------- | ----------------------------------------------------------- | | `Pending` | Created but not yet picked up by a worker. | | `Executing` | Worker is running the task. | | `Paused` | Worker paused (HITL approval, deep-planning question). | | `Completed` | Finished successfully. | | `Error` | Worker raised an exception. | | `Failed` | Task didn't complete successfully (lower-level than Error). | | `Stopped` | Manually terminated. | The `AgentExecutionStatus` enum (used everywhere status appears) has these values: `Pending`, `Executing`, `Paused`, `Error`, `Failed`, `Completed`, `Stopped`. String values are lowercase. ## Class-level method `Task.areport_external_task(...)` is a `@classmethod` that records an externally-executed run without going through `Backend`. It mirrors `Backend.areport_external_task` and exists for cases where you don't have a `Backend` instance handy. See [`report_external_task`](/developers/sdk-reference/tasks#report_external_task). ## create `Tasks.acreate` creates a new task. It's equivalent to `Agent.acreate_task` but accepts `agent_id` directly, so you don't need to load the `Agent` first. Use this when you only have an agent ID and want to skip the extra round-trip. ```python theme={"dark"} from xpander_sdk import Tasks tasks = Tasks() task = await tasks.acreate( agent_id="agent-123", prompt="Summarize the latest sales report", file_urls=["https://example.com/sales.csv"], ) print(task.id, task.status.value) ``` #### Parameters Identical to [`Agent.acreate_task`](/developers/sdk-reference/agents#create_task), with `agent_id` required up front: | Parameter | Type | Required | Default | Description | | ------------------------------ | ------------------------ | -------- | --------- | --------------------------------------------------- | | `agent_id` | `str` | Yes | – | Agent to invoke. | | `existing_task_id` | `str` | No | `None` | Continue an existing task. | | `prompt` | `str` | No | `""` | Natural-language input. | | `file_urls` | `list[str]` | No | `[]` | URLs of files to attach. | | `user_details` | `User` | No | `None` | End-user context. | | `agent_version` | `str` | No | `None` | Pin a specific agent version. | | `tool_call_payload_extension` | `dict` | No | `None` | Extra fields merged into every tool-call payload. | | `source` | `str` | No | `None` | Origin tag. | | `worker_id` | `str` | No | `None` | Pin to a specific worker. | | `run_locally` | `bool` | No | `False` | Mark as locally executed. | | `output_format` | `OutputFormat` | No | `None` | Output format. | | `output_schema` | `dict` | No | `None` | JSON schema. | | `events_streaming` | `bool` | No | `False` | Enables `task.aevents()`. | | `additional_context` | `str` | No | `None` | Extra context appended to system prompt. | | `instructions_override` | `str` | No | `None` | Extra instructions for this run. | | `test_run_node_id` | `str` | No | `None` | (Internal) Test workflow node. | | `user_oidc_token` | `str` | No | `None` | OIDC token for connector pre-auth. | | `expected_output` | `str` | No | `None` | Expected output description. | | `mcp_servers` | `list[MCPServerDetails]` | No | `[]` | Per-task MCP servers. | | `triggering_agent_id` | `str` | No | `None` | Triggering agent ID. | | `title` | `str` | No | `None` | Display title. | | `think_mode` | `ThinkMode` | No | `Default` | `Default` or `Harder`. | | `disable_attachment_injection` | `bool` | No | `False` | Skip auto-injection of human-readable file content. | | `return_metrics` | `bool` | No | `False` | Return metrics (Workflow → Agent only). | | `user_tokens` | `dict` | No | `None` | Pre-computed user tokens for MCP auth. | See [`Agent.acreate_task`](/developers/sdk-reference/agents#create_task) for parameter details and examples. #### Returns `Task` The created task. Starts in `Pending`. See [`Task`](/developers/sdk-reference/tasks#task-class). ### When to use this vs. `Agent.acreate_task` | Use | When | | ------------------------------------ | ---------------------------------------------------------------------------------------------------------------- | | `Tasks().acreate(agent_id=..., ...)` | You only have an `agent_id` (e.g. from a webhook or env var). One fewer round-trip than loading the agent first. | | `Agent.acreate_task(...)` | You already have the loaded `Agent` (e.g. inspecting its tools or graph first). | Both produce identical results; pick the one that matches what you have on hand. ### Sync version ```python theme={"dark"} task = tasks.create(agent_id="agent-123", prompt="Hello!") ``` ### Errors Raises [`ModuleException`](/developers/sdk-reference/overview#error-handling). Common statuses: | Status | Cause | | --------- | ----------------------------------------------------------------- | | 400 | Invalid input (bad output schema, malformed `mcp_servers`, etc.). | | 401 / 403 | Auth failure. | | 404 | Agent doesn't exist. | | 500 | Server error. | ## get `Tasks.aget` loads a full `Task` object: input, status, result, token usage, deep-planning state, attached files, and everything else stored against the task record. ```python theme={"dark"} from xpander_sdk import Tasks tasks = Tasks() task = await tasks.aget(task_id="task_xyz") print(task.status.value, task.result) ``` #### Parameters | Parameter | Type | Required | Description | | --------- | ----- | -------- | ----------- | | `task_id` | `str` | Yes | Task ID. | #### Returns `Task` A full `Task`. See the [`Task` class reference](/developers/sdk-reference/tasks#task-class) for attributes. ### Examples #### Wait for completion ```python theme={"dark"} import asyncio from xpander_sdk import AgentExecutionStatus terminal = { AgentExecutionStatus.Completed, AgentExecutionStatus.Failed, AgentExecutionStatus.Error, AgentExecutionStatus.Stopped, } while True: task = await tasks.aget(task_id=task.id) if task.status in terminal: break await asyncio.sleep(2) print(task.result) ``` For finer-grained progress, use `task.aevents()` instead: see [streaming events](/developers/sdk-reference/tasks#events). #### Reload an existing instance If you already have a `Task` instance and want fresh data, prefer `task.areload()` over a fresh `aget`: it preserves any in-flight `deep_planning` state that the API might briefly return as empty: ```python theme={"dark"} await task.areload() ``` #### Sync version ```python theme={"dark"} task = tasks.get(task_id="task_xyz") ``` ### Errors Raises [`ModuleException`](/developers/sdk-reference/overview#error-handling) on failure. Common statuses: | Status | Cause | | ------ | ------------------------------------------- | | 404 | Task doesn't exist (or wrong organization). | | 403 | Task exists but isn't accessible. | | 500 | Server error. | ## list `Tasks.alist` returns task summaries for a given agent. `Tasks.alist_user_tasks` does the same scoped to a single end-user across all agents. ```python theme={"dark"} from xpander_sdk import Tasks tasks = Tasks() items = await tasks.alist(agent_id="agent-123") for item in items: print(item.id, item.status.value, item.title or "(no title)") ``` #### Parameters | Parameter | Type | Required | Default | Description | | ---------- | ------ | -------- | ------- | --------------------------------------------------------------------------------------------------------------- | | `agent_id` | `str` | Yes | – | Agent whose tasks to list. | | `filters` | `dict` | No | `None` | Query filters. Supported keys: `user_id`, `parent_task_id`, `triggering_agent_id`, `status`, `internal_status`. | #### Returns `list[TasksListItem]` | Field | Type | Description | | --------------------- | ---------------------- | ---------------------------------------------- | | `id` | `str` | Task ID. | | `agent_id` | `str` | Owning agent. | | `user_id` | `str \| None` | End-user the task was created for. | | `parent_task_id` | `str \| None` | If this is a sub-task. | | `triggering_agent_id` | `str \| None` | If this task was kicked off by another agent. | | `organization_id` | `str` | Owning org. | | `status` | `AgentExecutionStatus` | Current status. | | `created_at` | `datetime \| None` | Creation timestamp. | | `updated_at` | `datetime \| None` | Last-update timestamp. | | `source_node_type` | `str \| None` | Trigger origin (`webhook`, `slack`, `sdk`, …). | | `result` | `str \| None` | Final result if completed. | | `title` | `str \| None` | Task title. | To load the full `Task` (including input, files, deep-planning state, tokens, activity log access), call `.aload()` on the item or pass `item.id` to `tasks.aget()`. ### Examples #### Filter by status ```python theme={"dark"} from xpander_sdk import AgentExecutionStatus failed = await tasks.alist( agent_id="agent-123", filters={"status": AgentExecutionStatus.Failed.value}, ) ``` The `status` filter accepts the lowercase string value: `"pending"`, `"executing"`, `"completed"`, `"failed"`, etc. #### Filter by end-user ```python theme={"dark"} mine = await tasks.alist( agent_id="agent-123", filters={"user_id": "user_42"}, ) ``` #### Tasks for a user `alist_user_tasks` searches across every agent the user has interacted with: ```python theme={"dark"} items = await tasks.alist_user_tasks(user_id="user_42") ``` | Parameter | Type | Required | Description | | --------- | ------ | -------- | ------------------------------------------- | | `user_id` | `str` | Yes | End-user identifier. | | `filters` | `dict` | No | Same filter keys as above, minus `user_id`. | #### Sync versions ```python theme={"dark"} items = tasks.list(agent_id="agent-123") items = tasks.list_user_tasks(user_id="user_42") ``` ### Errors Raises [`ModuleException`](/developers/sdk-reference/overview#error-handling) on failure. Common statuses: | Status | Cause | | --------- | --------------------------------------------- | | 401 / 403 | Auth failure or wrong organization. | | 404 | Agent doesn't exist (or you can't access it). | | 500 | Server error. | ## update `Tasks.aupdate` patches selected fields on a task. Pass only the fields you want to change: anything left as `None` is ignored. For finer control over save semantics (especially when mutating `Task` attributes locally first), use `task.asave()` on the instance. ```python theme={"dark"} from xpander_sdk import Tasks, AgentExecutionStatus tasks = Tasks() updated = await tasks.aupdate( task_id="task_xyz", status=AgentExecutionStatus.Completed, result="Final summary: …", ) print(updated.status.value) ``` #### Parameters | Parameter | Type | Required | Description | | ----------------------------- | ---------------------- | -------- | --------------------------------------------------------------- | | `task_id` | `str` | Yes | Task to update. | | `tool_call_payload_extension` | `dict` | No | Extra fields merged into every tool-call payload going forward. | | `source` | `str` | No | Update the origin tag. | | `status` | `AgentExecutionStatus` | No | New status. | | `last_executed_node_id` | `str` | No | Move the task's "current node" cursor (workflow agents). | | `result` | `str` | No | Final result string. | Fields with value `None` are stripped from the request: only what you pass is sent. #### Returns `Task` The freshly-loaded task with updates applied. See [`Task`](/developers/sdk-reference/tasks#task-class). ### Examples #### Mark complete ```python theme={"dark"} await tasks.aupdate( task_id="task_xyz", status=AgentExecutionStatus.Completed, result="Done", ) ``` #### Mark errored ```python theme={"dark"} await tasks.aupdate( task_id="task_xyz", status=AgentExecutionStatus.Error, result="Connector failed: 503 Service Unavailable", ) ``` #### Update only payload extension ```python theme={"dark"} await tasks.aupdate( task_id="task_xyz", tool_call_payload_extension={"headers": {"X-Trace-ID": "abc-123"}}, ) ``` This is rarely needed: payload extensions are usually set at task creation. Use this when you need to inject context after the task starts. ### Sync version ```python theme={"dark"} tasks.update(task_id="task_xyz", status=AgentExecutionStatus.Completed) ``` ### When to use this vs. `task.asave()` | Use | When | | ----------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `Tasks().aupdate(task_id=..., field=...)` | You only need to set a couple of fields and don't have a `Task` instance loaded. | | `task.asave()` | You've mutated the `Task` instance directly (e.g. set `task.result = "..."`). `asave` PATCHes everything except `configuration` and (by default) `deep_planning`. | The `@on_task` runtime auto-saves the task at the end of the handler: you don't usually call `aupdate` or `asave` yourself inside a handler. ### Errors Raises [`ModuleException`](/developers/sdk-reference/overview#error-handling). Common statuses: | Status | Cause | | ------ | --------------------------------------------- | | 404 | Task doesn't exist. | | 409 | Concurrent update conflict. Reload and retry. | | 500 | Server error. | ## stop `Tasks.astop` cancels a running task. The platform marks it `Stopped`, signals the worker to abandon its current step, and returns the updated record. ```python theme={"dark"} from xpander_sdk import Tasks tasks = Tasks() stopped = await tasks.astop(task_id="task_xyz") print(stopped.status.value, stopped.is_manually_stopped) # "stopped" True ``` #### Parameters | Parameter | Type | Required | Description | | --------- | ----- | -------- | ------------- | | `task_id` | `str` | Yes | Task to stop. | #### Returns `Task` The task record after the stop request was processed. `status` is `Stopped`, `is_manually_stopped` is `True`, and `finished_at` is set. ### Examples #### Stop from a running `Task` instance If you already have the `Task` object, prefer the instance method: ```python theme={"dark"} await task.astop() print(task.status.value) # "stopped" ``` `Task.astop()` and `Tasks().astop(task_id=task.id)` are equivalent: the instance method also updates the in-memory object. #### Idempotent stop Calling `astop` on an already-terminal task is safe: the platform returns the existing record without changing state. ```python theme={"dark"} # First call: stops it await tasks.astop(task_id="task_xyz") # Second call: no-op, returns the same record await tasks.astop(task_id="task_xyz") ``` ### Sync version ```python theme={"dark"} tasks.stop(task_id="task_xyz") ``` ### Errors Raises [`ModuleException`](/developers/sdk-reference/overview#error-handling). Common statuses: | Status | Cause | | ------ | ------------------- | | 404 | Task doesn't exist. | | 500 | Server error. | ## events `Task.aevents()` is an async generator over `TaskUpdateEvent`s emitted by the platform as the task runs: message chunks, tool-call requests/results, reasoning steps, sub-agent triggers, plan updates, and auth events. Use it to build live UIs or to react to specific event types in real time. ```python theme={"dark"} from xpander_sdk import TaskUpdateEventType # Task must be created with events_streaming=True task = await agent.acreate_task( prompt="Long-running research task", events_streaming=True, ) async for event in task.aevents(): print(event.type, event.task_id) if event.type == TaskUpdateEventType.TaskFinished: break ``` The task **must** be created with `events_streaming=True`. Calling `aevents()` on a non-streaming task raises `ValueError` immediately. #### Parameters None. #### Yields `TaskUpdateEvent` Each event has: | Field | Type | Description | | ----------------- | --------------------- | ------------------------------ | | `type` | `TaskUpdateEventType` | What kind of event. See below. | | `task_id` | `str` | Task this event belongs to. | | `organization_id` | `str` | Owning organization. | | `time` | `datetime` | Event timestamp. | | `data` | `Any` | Event-specific payload. | ##### Event types | `TaskUpdateEventType` | When | `data` payload | | --------------------- | ------------------------------------------------------------ | ----------------------------------------------------------------------- | | `TaskCreated` | Task is created. | A `Task` object. | | `TaskUpdated` | Any non-final task mutation (status change, result patched). | A `Task` object. | | `TaskFinished` | Task reaches a terminal state. | A `Task` object. | | `Chunk` | Streaming text from the LLM. | `str` (text chunk). | | `AuthEvent` | Auth required (MCP OAuth, ECA). | Auth-specific dict. Also dispatched to `@on_auth_event` handlers. | | `ToolCallRequest` | Agent invokes a tool. | A `ToolCallRequest` (operation\_id, tool\_name, payload, reasoning, …). | | `ToolCallResult` | Tool finishes. | A `ToolCallResult` (operation\_id, result, is\_error, …). | | `SubAgentTrigger` | A sub-agent task is created. | Triggering details. | | `Think` | Reasoning step (think tool). | Reasoning data. | | `Analyze` | Reasoning step (analyze tool). | Reasoning data. | | `PlanUpdated` | Deep-planning state changes. | A `DeepPlanning` object. | | `TaskCompactization` | Auto-compaction event (Layer 2). | A `TaskCompactizationEvent`. | If a typed payload fails to parse (e.g. due to schema drift), the SDK still yields the event with `data` set to the raw dict: the envelope (`type`, `task_id`, `time`) always propagates. ### Examples #### Filter on event type ```python theme={"dark"} async for event in task.aevents(): if event.type == TaskUpdateEventType.Chunk: print(event.data, end="", flush=True) elif event.type == TaskUpdateEventType.TaskFinished: print() break ``` `Chunk` events have a string `data` payload (the streaming text), making it easy to render token-by-token output. #### Render tool calls ```python theme={"dark"} async for event in task.aevents(): if event.type == TaskUpdateEventType.ToolCallRequest: req = event.data print(f"→ {req.tool_name}({req.payload})") elif event.type == TaskUpdateEventType.ToolCallResult: res = event.data status = "✗" if res.is_error else "✓" print(f"{status} {res.tool_name}: {res.result}") ``` #### Stop on first failure ```python theme={"dark"} async for event in task.aevents(): if event.type == TaskUpdateEventType.ToolCallResult and event.data.is_error: print("Tool failed, stopping.") await task.astop() break ``` #### Track auth flows in-band ```python theme={"dark"} async for event in task.aevents(): if event.type == TaskUpdateEventType.AuthEvent: print(f"Auth required: {event.data}") # Show URL to user, etc. ``` If you've registered an `@on_auth_event` handler, it fires automatically: the in-band event lets you also handle it inline. ### Sync version ```python theme={"dark"} for event in task.events(): print(event.type, event.data) ``` `task.events()` consumes the async generator on a synchronous executor and yields events in order. Don't call from inside a running event loop. ### Lifecycle The generator reconnects automatically if the SSE stream drops mid-task. It exits when: 1. The platform closes the stream (typically after `TaskFinished`). 2. The connection fails permanently (network, auth). 3. You `break` out of the loop. ### Errors * `ValueError`: task wasn't created with `events_streaming=True`. * Network failures propagate after the SSE retry budget is exhausted. ### When *not* to stream For batch jobs that don't care about progress, skip `events_streaming` and poll `task.areload()` (or use webhooks). Streaming holds an HTTP connection open per task: fine for one or two, expensive for hundreds. ## get\_activity\_log `Task.aget_activity_log` returns the full thread of activity for a task: user messages, assistant messages, tool calls, tool results, reasoning steps, sub-agent triggers, and auth events. Unlike `task.aevents()` (live SSE for in-flight tasks), the activity log is a historical record you can fetch at any time, including for completed tasks. ```python theme={"dark"} from xpander_sdk import Tasks from xpander_sdk.models.activity import ( AgentActivityThreadMessage, AgentActivityThreadToolCall, AgentActivityThreadReasoning, ) task = await Tasks().aget(task_id="task_xyz") log = await task.aget_activity_log() for msg in log.messages: if isinstance(msg, AgentActivityThreadMessage): print(f"[{msg.role}] {msg.content.text}") elif isinstance(msg, AgentActivityThreadToolCall): print(f"[tool] {msg.tool_name}({msg.payload}) → {msg.result}") elif isinstance(msg, AgentActivityThreadReasoning): print(f"[reasoning:{msg.type}] {msg.thought}") ``` #### Parameters None. #### Returns `AgentActivityThread` | Field | Type | Description | | -------------- | ---------------------------- | ----------------------------------------------------- | | `messages` | `list[AgentActivityThread*]` | Ordered union of message types (see below). | | (other fields) | – | Thread metadata (id, agent\_id, organization\_id, …). | The messages list is a tagged union. Common variants: | Type | Fields | | ------------------------------ | ---------------------------------------------------------- | | `AgentActivityThreadMessage` | `role`, `content.text` (string), `content` (rich content). | | `AgentActivityThreadToolCall` | `tool_name`, `payload`, `result`. | | `AgentActivityThreadReasoning` | `type` (`"think"` / `"analyze"`), `thought`. | (There are additional sub-types for sub-agent triggers and auth events: branch on `isinstance` or `type(msg).__name__` to handle them.) ### Examples #### Just the user/assistant transcript ```python theme={"dark"} log = await task.aget_activity_log() for msg in log.messages: if isinstance(msg, AgentActivityThreadMessage): print(f"{msg.role.upper()}: {msg.content.text}") ``` #### Audit tool usage ```python theme={"dark"} log = await task.aget_activity_log() tool_calls = [m for m in log.messages if isinstance(m, AgentActivityThreadToolCall)] print(f"Task {task.id} called {len(tool_calls)} tools:") for tc in tool_calls: print(f" - {tc.tool_name}") ``` #### Reasoning trace ```python theme={"dark"} reasoning = [ m for m in log.messages if isinstance(m, AgentActivityThreadReasoning) ] for r in reasoning: print(f"[{r.type}] {r.thought}") ``` ### Sync version ```python theme={"dark"} log = task.get_activity_log() ``` ### Errors Raises [`ModuleException`](/developers/sdk-reference/overview#error-handling) if the activity log can't be retrieved: | Status | Cause | | ------ | ------------------------------------------------- | | 404 | Task has no activity log (e.g. it never started). | | 500 | Server error or network failure. | ## report\_metrics `Task.areport_metrics` records the task's token usage, tool calls, and execution outcome to the platform's metrics store. The `@on_task` runtime calls this automatically at the end of every handler if `task.tokens` is set, so you only need to invoke it directly when you're driving a task outside the runtime. ```python theme={"dark"} from xpander_sdk import Tokens task.tokens = Tokens(prompt_tokens=2_140, completion_tokens=380) task.used_tools = ["web_search", "fetch_pdf"] task.duration = 4.7 await task.areport_metrics() ``` `task.tokens` must be set before calling `areport_metrics`. The method raises `ValueError` if `tokens` is missing. #### Parameters | Parameter | Type | Required | Description | | --------------- | --------------- | -------- | ----------------------------------------------------------------------------------- | | `configuration` | `Configuration` | No | Override SDK config. Falls back to `task.configuration`, then env-derived defaults. | #### Returns `None`. ### What gets reported The metrics report includes: * `execution_id`: task id. * `source`: task source. * `memory_thread_id`: same as task id (memory and execution share an id). * `task`: input text (`task.input.text`). * `status`: current `task.status`. * `internal_status`: current `task.internal_status`. * `ai_model`: fixed to `"xpander"`. * `api_calls_made`: tool names from `task.used_tools` (or `[]` for orchestration tasks with `return_metrics=True`). * `result`: final result string. * `llm_tokens`: token counts wrapped in `ExecutionTokens(worker=task.tokens)`. ### Examples #### Inside a custom event loop If you're driving an agent without `@on_task`, report metrics manually before returning to the caller: ```python theme={"dark"} from xpander_sdk import Backend, Tokens from xpander_sdk.modules.tasks.sub_modules.task import Task backend = Backend() task = await backend.ainvoke_agent(agent_id="agent-123", prompt="...") # ... run the agent yourself, track tokens ... task.tokens = Tokens(prompt_tokens=1_500, completion_tokens=320) task.used_tools = ["search", "summarize"] task.duration = 3.1 await task.areport_metrics() ``` This makes the run show up in the dashboard with proper token accounting. #### Sync version ```python theme={"dark"} task.report_metrics() ``` ### Errors Raises [`ModuleException`](/developers/sdk-reference/overview#error-handling) on persistence failures, or `ValueError` if `task.tokens` is `None`. ## report\_external\_task `Task.areport_external_task` is the `@classmethod` version of [`Backend.areport_external_task`](/developers/sdk-reference/backend#report_external_task). It logs a task that was executed outside the xpander.ai runtime so it appears in task history and metrics. Use this form when you don't have a `Backend` instance in scope but do have a `Configuration`. ```python theme={"dark"} from xpander_sdk import Task, Tokens, Configuration config = Configuration() # picks up env vars task = await Task.areport_external_task( configuration=config, agent_id="agent-123", id="ext-job-9921", input="Summarize Q4 earnings", result="Q4 revenue grew 22% YoY, driven by ...", tokens=Tokens(prompt_tokens=2_140, completion_tokens=380), duration=4.7, used_tools=["web_search", "fetch_pdf"], is_success=True, ) ``` #### Parameters | Parameter | Type | Required | Default | Description | | --------------- | --------------- | -------- | --------------------- | ------------------------------------------------------------------- | | `configuration` | `Configuration` | No | New `Configuration()` | SDK config (api\_key + organization\_id). | | `agent_id` | `str` | Yes | – | Agent the run belongs to. | | `id` | `str` | No | `None` | External task id. Re-using the same id updates the existing record. | | `input` | `str` | No | `None` | Run input. | | `llm_response` | `Any` | No | `None` | Raw provider response. Stored verbatim. | | `tokens` | `Tokens` | No | `None` | Token usage. | | `is_success` | `bool` | No | `True` | Pass/fail. | | `result` | `str` | No | `None` | Final result. | | `duration` | `float` | No | `0` | Wall-clock seconds. | | `used_tools` | `list[str]` | No | `[]` | Tool names. | #### Returns `Task` The platform-side `Task` after persistence. Carries the `id`, `status`, and timestamps assigned by the cloud. ### When to use this vs. `Backend.areport_external_task` Functionally identical. `Backend.areport_external_task` is more discoverable (it sits next to the other Backend methods you'd be using); this classmethod is convenient when you don't want to instantiate `Backend`. ```python theme={"dark"} # Equivalent ways to record an external run: # 1. Backend backend = Backend(configuration=config) await backend.areport_external_task(agent_id="agent-123", id="ext-001", ...) # 2. Task classmethod await Task.areport_external_task(configuration=config, agent_id="agent-123", id="ext-001", ...) ``` See the [`Backend` page](/developers/sdk-reference/backend#report_external_task) for typical usage patterns (idempotent updates, failure reporting). ### Sync version ```python theme={"dark"} Task.report_external_task(configuration=config, agent_id="agent-123", id="ext-001", ...) ``` ## Task class `Task` represents a single agent execution. You get one back from `Agent.acreate_task`, `Tasks.aget`, `Tasks.acreate`, and the `@on_task` handler. It carries the full task state (input, status, result, deep-planning, tokens, …) and the methods needed to drive it forward. ```python theme={"dark"} from xpander_sdk import Tasks task = await Tasks().aget(task_id="task_xyz") print(task.id, task.status.value, task.result) ``` ### Class methods #### `Task.aload(task_id, configuration=None) -> Task` Same as `Tasks.aget` but available without a `Tasks` instance. Useful when you have a `Configuration` but don't want to instantiate the module class. ```python theme={"dark"} from xpander_sdk import Task, Configuration config = Configuration(api_key="...", organization_id="...") task = await Task.aload(task_id="task_xyz", configuration=config) ``` The sync sibling is `Task.load(...)`. #### `Task.areport_external_task(...)` (classmethod) See the dedicated [`report_external_task`](/developers/sdk-reference/tasks#report_external_task) page. ### Attributes #### Identity | Attribute | Type | Description | | --------------------- | ------------- | ------------------------------------------------ | | `id` | `str` | Task ID. | | `agent_id` | `str` | Owning agent. | | `organization_id` | `str` | Owning organization. | | `agent_version` | `str \| None` | Agent version pinned for this run. | | `triggering_agent_id` | `str \| None` | Agent that triggered this (sub-agent flows). | | `parent_execution` | `str \| None` | Parent task ID for sub-tasks. | | `sub_executions` | `list[str]` | Child task IDs. | | `source` | `str \| None` | Origin tag (`"sdk"`, `"webhook"`, `"slack"`, …). | | `title` | `str \| None` | Display title. | #### Input | Attribute | Type | Description | | ------------------------------ | ------------------------ | ----------------------------------------------------------- | | `input` | `AgentExecutionInput` | Holds `text`, `files: list[str]`, and `user: User \| None`. | | `payload_extension` | `dict \| None` | Extra fields merged into every tool-call payload. | | `additional_context` | `str \| None` | Extra context appended to the system prompt. | | `instructions_override` | `str \| None` | Extra instructions for this run. | | `expected_output` | `str \| None` | Expected output description. | | `mcp_servers` | `list[MCPServerDetails]` | Per-task MCP servers. | | `user_oidc_token` | `str \| None` | OIDC token for connector pre-auth. | | `user_tokens` | `dict \| None` | Pre-computed user tokens for MCP auth. | | `disable_attachment_injection` | `bool` | Skip auto-inlining of human-readable file content. | | `output_format` | `OutputFormat \| None` | Output format. | | `output_schema` | `dict \| None` | JSON schema for structured output. | | `voice_id` | `str \| None` | Voice ID for `OutputFormat.Voice`. | | `think_mode` | `ThinkMode` | `Default` or `Harder`. | #### State | Attribute | Type | Description | | ----------------------- | ------------------------------- | ----------------------------------------------------------------------------------- | | `status` | `AgentExecutionStatus` | One of `Pending`, `Executing`, `Paused`, `Error`, `Failed`, `Completed`, `Stopped`. | | `internal_status` | `str \| None` | Finer-grained status used by the platform internally. | | `last_executed_node_id` | `str \| None` | Cursor in the execution graph (workflow agents). | | `is_manually_stopped` | `bool` | `True` after `astop`. | | `is_orchestration` | `bool` | `True` for orchestration tasks. | | `events_streaming` | `bool` | Whether SSE streaming is enabled. | | `hitl_request` | `HumanInTheLoopRequest \| None` | Set when the task is paused awaiting human approval. | | `pending_eca_request` | `PendingECARequest \| None` | Set when an ECA (External Credential Authorization) is pending. | | `deep_planning` | `DeepPlanning` | Deep-planning state (plan items, completion flags). | | `execution_attempts` | `int` | Number of plan-following attempts (1 for first execution). | | `return_metrics` | `bool` | Whether the task returns metrics. | #### Output | Attribute | Type | Description | | ------------ | ---------------- | ---------------------------------- | | `result` | `str \| None` | Final result. | | `tokens` | `Tokens \| None` | Token usage (prompt + completion). | | `used_tools` | `list[str]` | Names of tools the task invoked. | | `duration` | `float` | Wall-clock duration in seconds. | #### Timestamps | Attribute | Type | Description | | ------------- | ------------------ | --------------------------------- | | `created_at` | `datetime` | Creation timestamp. | | `started_at` | `datetime \| None` | When the worker picked it up. | | `paused_at` | `datetime \| None` | When it last paused. | | `finished_at` | `datetime \| None` | When it reached a terminal state. | #### Internal | Attribute | Type | Description | | ------------------ | ----------------------- | ----------------------------------------------- | | `configuration` | `Configuration \| None` | SDK configuration. Excluded from serialization. | | `test_run_node_id` | `str \| None` | (Internal) Test workflow node id. | ### Instance methods #### `save` `task.asave(with_deep_plan_update: bool = False)`: PATCHes the task on the platform with the current in-memory state. By default `deep_planning` is excluded (the platform's plan state is authoritative); pass `with_deep_plan_update=True` to push your plan updates back. ```python theme={"dark"} task.result = "Done" task.status = AgentExecutionStatus.Completed await task.asave() ``` After saving, the response repopulates the local instance, but `deep_planning` and `additional_context` are restored from local memory if the API returns empty values (defensive against stale API state during retries). Sync: `task.save(...)`. #### `set_status` `task.aset_status(status, result=None)`: convenience wrapper that sets `status` (and optionally `result`) and calls `asave()` in one step. ```python theme={"dark"} await task.aset_status(AgentExecutionStatus.Executing) ``` Sync: `task.set_status(...)`. #### `stop` `task.astop()`: terminates the task and updates the local instance with the platform's response. Sync: `task.stop()`. #### `reload` `task.areload()`: re-fetches the task from the platform and updates the in-memory instance. `deep_planning` and `additional_context` are restored from local memory if the API returns empty values. Sync: `task.reload()`. #### `events` `task.aevents()` / `task.events()`: SSE stream of `TaskUpdateEvent`. Requires `events_streaming=True` at task creation. See [streaming events](/developers/sdk-reference/tasks#events). #### `get_activity_log` `task.aget_activity_log()` / `task.get_activity_log()`: full message / tool-call / reasoning thread for the task. See [activity log](/developers/sdk-reference/tasks#get_activity_log). #### `report_metrics` `task.areport_metrics()` / `task.report_metrics()`: pushes token counts and tool usage to the platform. See [report metrics](/developers/sdk-reference/tasks#report_metrics). #### `get_plan_following_status` `task.aget_plan_following_status() -> PlanFollowingStatus`: checks whether deep-planning tasks are complete. Returns `PlanFollowingStatus(can_finish: bool, uncompleted_tasks: list[DeepPlanningItem])`. Used by the runtime to retry the agent until the plan is satisfied. Sync: `task.get_plan_following_status()`. #### `acompact_session_for_retry` `task.acompact_session_for_retry() -> CompactRetryResult`: forces L2 (auto) compaction on the agent's session before a plan-following retry. Used internally by the runtime; rarely needed from user code. #### Agno helpers These methods help shape the task input for Agno agents. ##### `get_files` ```python theme={"dark"} task.get_files() -> list[Any] ``` Returns PDF files from `task.input.files` as Agno `File` objects (when Agno is installed). Returns the URL strings as a fallback. Empty list if the task has no PDFs. ##### `get_images` ```python theme={"dark"} task.get_images() -> list[Any] ``` Returns image files as Agno `Image` objects (or URL strings as fallback). Empty list if no images. ##### `get_human_readable_files` ```python theme={"dark"} task.get_human_readable_files() -> list[dict[str, str]] ``` Fetches and parses text-based files (CSV, JSON, TXT, .py, …) and returns `[{"url": ..., "content": ...}]`. Used by `to_message()` to inline file contents into the prompt. Honors `task.disable_attachment_injection`. ##### `to_message` ```python theme={"dark"} task.to_message(retry_count: int = 0) -> str ``` Builds the message string to pass to the framework agent. Format: ``` {input.text} Files: url1, url2, ... Files contents: {json of each readable file} ``` On retries (`retry_count > 0`) and when deep planning is active, it generates a continuation prompt that lists completed/uncompleted tasks and pinpoints the next one to work on. This is the prompt format the runtime feeds to Agno when retrying after an incomplete plan. ```python theme={"dark"} @on_task async def handler(task: Task) -> Task: args = await backend.aget_args(agent_id=task.agent_id, task=task) agno_agent = AgnoAgent(**args) result = await agno_agent.arun( input=task.to_message(), # text + files + readable contents files=task.get_files(), # PDFs as Agno File images=task.get_images(), # images as Agno Image ) task.result = result.content return task ``` # Tools Source: https://docs.xpander.ai/developers/sdk-reference/tools Discover, register, and invoke tools (both backend-managed and locally registered). `ToolsRepository` is the registry that holds every tool an agent can call. There are two kinds: * **Backend tools**: connectors and OpenAPI imports configured in the Workbench. Loaded automatically when you `agents.aget(...)` an agent. * **Local tools**: Python functions you decorate with [`@register_tool`](/developers/sdk-reference/tools#register_tool-classmethod). Registered in-process and merged into the agent's tool list. You don't usually instantiate `ToolsRepository` directly: accessing `agent.tools` gives you the configured instance for that agent. ```python theme={"dark"} agent = await agents.aget("agent-123") # All tools (backend + local) merged into one list for tool in agent.tools.list: print(tool.id, tool.name, tool.is_local) # Look up by id or name weather = agent.tools.get_tool_by_id("get_weather") weather2 = agent.tools.get_tool_by_name("Weather") # Framework-ready callables (used internally by Backend.aget_args) fns = agent.tools.functions ``` ## Class layout | Type | Reference | | -------------------------- | ------------------------------------------------------------------------------------------------------ | | `ToolsRepository` | This page | | `Tool` | [Tool class](/developers/sdk-reference/tools#tool-class) | | `@register_tool` decorator | [register\_tool](/developers/sdk-reference/tools#register_tool-classmethod) | | MCP types | [MCP](/developers/sdk-reference/tools#mcp-types) | | Tool lifecycle hooks | [`@on_tool_*`](/developers/sdk-reference/decorators#@on_tool_before-/-@on_tool_after-/-@on_tool_error) | ## Constructor ```python theme={"dark"} ToolsRepository( configuration: Optional[Configuration] = None, tools: List[Tool] = [], agent_graph: Optional[AgentGraph] = None, is_async: bool = True, ) ``` | Parameter | Type | Default | Description | | --------------- | --------------- | ----------------- | ---------------------------------------------------- | | `configuration` | `Configuration` | `Configuration()` | SDK configuration. | | `tools` | `list[Tool]` | `[]` | Backend-managed tools to seed the repository. | | `agent_graph` | `AgentGraph` | `None` | Owning agent's graph (for schema overrides). | | `is_async` | `bool` | `True` | Whether `.functions` should produce async callables. | In practice, `agents.aget(...)` constructs a `ToolsRepository` for you with all four arguments populated. ## Properties ### `list` ```python theme={"dark"} agent.tools.list -> list[Tool] ``` A merged list of backend tools and locally-registered tools (de-duplicated by `id`). Each tool has its `Configuration` set and any agent-graph schema overrides applied. ### `functions` ```python theme={"dark"} agent.tools.functions -> list[Callable[..., Any]] ``` Framework-ready callables for every tool in `.list`. Each callable accepts a single `payload` argument validated against the tool's auto-generated Pydantic schema. The callable's `__name__` is the tool id and its `__doc__` includes a usage example. This is what `Backend.aget_args` injects into your framework agent's `tools=...` parameter: you rarely need it directly. Useful when binding tools to a custom framework manually. ## Methods ### `get_tool_by_id` ```python theme={"dark"} agent.tools.get_tool_by_id("get_weather") -> Tool | None ``` Returns the tool with the matching `id`, or `None`. ### `get_tool_by_name` ```python theme={"dark"} agent.tools.get_tool_by_name("Weather") -> Tool | None ``` Returns the tool with the matching `name` (display name), or `None`. ### `register_tool` (classmethod) ```python theme={"dark"} ToolsRepository.register_tool(tool: Tool) ``` Adds a tool to the global local registry. Used by the `@register_tool` decorator: you don't usually call this directly. ### `should_sync_local_tools` ```python theme={"dark"} agent.tools.should_sync_local_tools() -> bool ``` Returns `True` when at least one local tool is marked `should_add_to_graph=True` and hasn't been synced yet. ### `get_local_tools_for_sync` ```python theme={"dark"} agent.tools.get_local_tools_for_sync() -> list[Tool] ``` Returns local tools awaiting sync (used internally during `agent.aload`). ### `aload_tool_by_id` ```python theme={"dark"} await agent.tools.aload_tool_by_id("_") -> None ``` Standalone tool loading: looks up a tool by its `_` form and seeds it into the repository. Useful when you want to invoke a single tool without loading an agent. The id is the connector's UUID and the operation's catalog id joined by a single underscore, for example `"07687ac7-d474-4d24-8ec6-6debac476b00_6a581606eaade0ae8b8f2c9c"`. Both halves come from [List Connector Operations](/api-reference/v1/tools/list-connector-operations). The sync sibling is `load_tool_by_id`. ## Patterns ### Iterate every tool ```python theme={"dark"} agent = await agents.aget("agent-123") for tool in agent.tools.list: print(f"- {tool.id}: {tool.description[:60]}") ``` ### Bind tools to a custom framework ```python theme={"dark"} fns = agent.tools.functions # list of callables, each accepts `payload` # Pass directly to a framework that expects callables: my_framework_agent = MyAgent(tools=fns) ``` ### Standalone invocation (no agent context) ```python theme={"dark"} from xpander_sdk import ToolsRepository repo = ToolsRepository() await repo.aload_tool_by_id("07687ac7-d474-4d24-8ec6-6debac476b00_6a581606eaade0ae8b8f2c9c") tool = repo.list[0] invoke = tool.get_invocation_function(is_async=True) result = await invoke({"channel": "#general", "text": "Hello"}) ``` This pattern is how you call a single platform connector without going through an agent. ## @register\_tool `@register_tool` turns a Python function into a tool the agent can invoke. The SDK extracts type hints and the docstring to build a schema and description automatically: there's no manual schema writing. ```python theme={"dark"} from xpander_sdk import register_tool @register_tool def calculate_sum(a: int, b: int) -> int: """Add two numbers.""" return a + b ``` After this runs (typically at module import), `calculate_sum` is available to every `Agents().aget(...)` call as a local tool with id `"calculate_sum"`. ### Decorator forms ```python theme={"dark"} @register_tool # plain def fn(...): ... @register_tool(add_to_graph=True) # with options def fn(...): ... ``` | Parameter | Type | Default | Description | | -------------- | ------ | ------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `add_to_graph` | `bool` | `False` | When `True`, the tool is pushed into the agent's execution graph (so the platform routes calls through it). When `False`, the tool is only available in-process. | ### What it does 1. Inspects the function's parameters and type hints. 2. Builds a Pydantic model (`Args`) from the parameters: required if no default, optional otherwise. 3. Constructs a `Tool` with: * `id` = function name * `name` = function name * `description` = function docstring * `parameters` = generated JSON schema * `fn` = the function * `is_local = True` * `should_add_to_graph = add_to_graph` 4. Registers the tool in `ToolsRepository`'s class-level `_local_tools` list (process-wide singleton). 5. Returns the original function unchanged: `calculate_sum(2, 3)` still works as plain Python. ### Examples #### Async functions are supported ```python theme={"dark"} @register_tool async def fetch_url(url: str) -> str: """Fetch the body of a URL.""" async with httpx.AsyncClient() as client: response = await client.get(url) return response.text ``` When the agent calls this tool, the SDK awaits the coroutine. #### Optional parameters ```python theme={"dark"} @register_tool def search(query: str, limit: int = 10, region: str = "US") -> list[str]: """Search the catalog. Returns matching SKUs.""" ... ``` Defaults become optional fields in the JSON schema. #### Push to the agent graph ```python theme={"dark"} @register_tool(add_to_graph=True) async def analyze_data(data: list, analysis_type: str) -> dict: """Analyze incoming data; returns aggregated metrics.""" ... ``` `add_to_graph=True` makes the tool visible in the platform's graph view for the next `agents.aget(...)`: the SDK sync runs in the background after `aget` returns. #### Use the function directly ```python theme={"dark"} @register_tool def add(a: int, b: int) -> int: """Add two ints.""" return a + b # Still callable as a regular function add(2, 3) # 5 ``` ### Visibility rules The decorator registers tools at module-import time on a process-wide registry. That means: * Every agent loaded by `Agents().aget(...)` in this process inherits the local tools. * Tools defined inside a function body register the **first** time the function runs, but stay registered for the rest of the process's lifetime. * If you `del` or rename a function after decoration, the registered `Tool` keeps its captured reference (the `fn` attribute): it doesn't unregister itself. For per-invocation tools, use `Backend.aget_args(tools=[fn])` instead: that adds callables to one specific `aget_args` call without polluting the global registry. ### Schema details The generated schema uses Pydantic's `model_json_schema(mode="serialization")`. Parameter names, types, and defaults map directly: ```python theme={"dark"} @register_tool def book_flight(origin: str, destination: str, date: str = "tomorrow") -> dict: """Book a flight.""" ... ``` generates roughly: ```json theme={"dark"} { "properties": { "origin": {"type": "string", "title": "Origin"}, "destination": {"type": "string", "title": "Destination"}, "date": {"type": "string", "title": "Date", "default": "tomorrow"} }, "required": ["origin", "destination"], "title": "BookFlightArgs", "type": "object" } ``` The agent's LLM sees this schema; the docstring becomes the tool's description. Write docstrings the way you'd write a tool description: that's exactly what the LLM reads. ### Related * [`Tool` class](/developers/sdk-reference/tools#tool-class): what the decorator creates. * [`@on_tool_before` / `@on_tool_after` / `@on_tool_error`](/developers/sdk-reference/decorators#@on_tool_before-/-@on_tool_after-/-@on_tool_error): lifecycle hooks around any tool invocation. ## Tool class `Tool` represents a single callable an agent can invoke: a connector operation, an OpenAPI endpoint, an MCP tool, or a local Python function registered with `@register_tool`. You normally get one from `agent.tools.list` or `agent.tools.get_tool_by_id(...)`. ```python theme={"dark"} agent = await agents.aget("agent-123") tool = agent.tools.get_tool_by_id("get_weather") print(tool.id, tool.name, tool.description) print(tool.parameters) # raw JSON schema print(tool.schema) # Pydantic model class generated from parameters ``` ### Attributes | Attribute | Type | Description | | --------------------- | ------------------------------ | ------------------------------------------------------------------------------- | | `id` | `str` | Tool identifier (used as the function name when invoked by the LLM). | | `name` | `str` | Display name. | | `method` | `str` | HTTP method for remote invocation (`"POST"`, `"GET"`, …). | | `path` | `str` | Endpoint path. | | `description` | `str` | Human-readable description (used by the LLM to decide when to call). | | `parameters` | `dict` | JSON schema for the input payload. | | `is_local` | `bool` | `True` when the tool is a `@register_tool` Python function. | | `is_synced` | `bool` | For local tools: `True` after the tool has been pushed to the platform's graph. | | `is_standalone` | `bool` | `True` when loaded via `aload_tool_by_id` (no agent context). | | `should_add_to_graph` | `bool` | Whether this tool should be added to agent execution graphs. | | `connector_id` | `str \| None` | For platform tools: the connector id. | | `operation_id` | `str \| None` | For platform tools: the operation id. | | `schema_overrides` | `AgentGraphItemSchema \| None` | Per-agent input/output schema overrides. | | `fn` | `Callable \| None` | The Python function for local tools. Excluded from serialization. | | `configuration` | `Configuration` | SDK configuration. | ### Computed properties #### `schema` ```python theme={"dark"} tool.schema -> type[BaseModel] ``` A dynamically-generated Pydantic model class derived from `tool.parameters`. The model's name is `{ToolIdPascalCase}PayloadSchema`. If the agent has schema overrides for this tool, they're applied here. ```python theme={"dark"} WeatherSchema = tool.schema WeatherSchema(city="NYC") # validates input ``` #### `payload_schema` ```python theme={"dark"} tool.payload_schema -> type[BaseModel] ``` A wrapper schema with a single `payload` field whose type is `tool.schema`. Useful when a framework expects every tool call to be wrapped in `{"payload": {...}}`. ```python theme={"dark"} PayloadModel = tool.payload_schema PayloadModel(payload={"city": "NYC"}) ``` ### Methods #### `ainvoke` / `invoke` Invoke the tool. Validates the payload against `tool.schema`, executes locally (`is_local=True`) or remotely, and returns a `ToolInvocationResult`. ```python theme={"dark"} result = await tool.ainvoke( agent_id="agent-123", payload={"city": "Tokyo"}, ) print(result.result, result.is_success) ``` | Parameter | Type | Required | Default | Description | | ------------------- | --------------- | -------- | ------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `agent_id` | `str` | Yes | – | Agent invoking the tool. | | `payload` | `Any` | Yes | – | Tool input. Validated against `tool.schema`. | | `agent_version` | `str` | No | `None` | Pin to a specific agent version. | | `payload_extension` | `dict` | No | `{}` | Extra fields deep-merged into the payload (headers, auth, etc.). | | `configuration` | `Configuration` | No | Tool's config | Override SDK configuration. | | `task_id` | `str` | No | `None` | Associate with a task (for activity logging). | | `tool_call_id` | `str` | No | `None` | Correlation id matching the LLM's tool-call id. | | `report_activity` | `bool` | No | `False` | Push `ToolCallRequest` / `ToolCallResult` events to the task activity log. Set this when invoking outside the framework's tool hook (so events aren't double-emitted). | Returns a `ToolInvocationResult` (see below). Sync sibling: `tool.invoke(...)`. `ainvoke` runs the configured [tool lifecycle hooks](/developers/sdk-reference/decorators#@on_tool_before-/-@on_tool_after-/-@on_tool_error) (`@on_tool_before` / `@on_tool_after` / `@on_tool_error`) around the call. #### `acall_remote_tool` / `call_remote_tool` Lower-level: makes the API call without local-tool fallback or hook execution. Used internally by `ainvoke` when `is_local=False`. Use directly only for advanced cases (preflight checks, custom invocation pipelines). ```python theme={"dark"} result = await tool.acall_remote_tool( agent_id="agent-123", payload={"city": "Tokyo"}, ) ``` #### `agraph_preflight_check` / `graph_preflight_check` Asks the platform to validate a hypothetical tool invocation without executing it. Used internally for graph routing. #### `get_invocation_function` ```python theme={"dark"} tool.get_invocation_function( is_async: bool = False, configuration: Optional[Configuration] = None, ) -> Callable ``` Factory that returns a pre-configured invocation function bound to this tool's connector + configuration. Use for standalone invocation (no agent context): ```python theme={"dark"} invoke = tool.get_invocation_function(is_async=True) result = await invoke({"city": "NYC"}) # ToolInvocationResult ``` This skips agent-id and task-id binding: the underlying call hits the connector via `connector_id_operation_id` and returns the raw response wrapped in `ToolInvocationResult`. Use it after `ToolsRepository.aload_tool_by_id(...)` to call a single connector without an agent. ### `ToolInvocationResult` The shape returned by `ainvoke` and the standalone invocation function. | Field | Type | Description | | -------------- | ------------- | ------------------------------ | | `tool_id` | `str` | The tool's id. | | `tool_call_id` | `str \| None` | The correlation id, if passed. | | `task_id` | `str \| None` | The task id, if passed. | | `payload` | `Any` | The payload that was sent. | | `status_code` | `int` | HTTP status (200 by default). | | `result` | `Any` | The tool's response. | | `is_success` | `bool` | `True` on 2xx. | | `is_error` | `bool` | `True` on failure. | | `is_local` | `bool` | `True` for local tools. | `is_success` and `is_error` are mutually exclusive in normal operation: check `is_error` first to branch on failure cases. ### Examples #### Inspect tool schema ```python theme={"dark"} tool = agent.tools.get_tool_by_id("get_weather") # Pydantic schema (from parameters) schema = tool.schema print(schema.model_json_schema()) # Validate a payload before sending schema.model_validate({"city": "NYC"}) # raises ValidationError on bad shape ``` #### Per-call configuration override ```python theme={"dark"} from xpander_sdk import Configuration custom_config = Configuration(api_key="other-key", organization_id="other-org") result = await tool.ainvoke( agent_id="agent-123", payload={"city": "Berlin"}, configuration=custom_config, ) ``` #### Reporting activity for non-Agno callers When invoking a tool outside an Agno-driven flow (e.g. from your own agent loop), set `report_activity=True` so the call shows up in the task's activity log: ```python theme={"dark"} result = await tool.ainvoke( agent_id="agent-123", task_id=task.id, payload={...}, report_activity=True, ) ``` Inside Agno-driven flows, leave it at `False`: the Agno hook reports the call automatically and you'd otherwise double-emit events. ## MCP types The Model Context Protocol (MCP) lets agents connect to external tool servers. The SDK exposes `MCPServerDetails` for declaring servers per task, and a few enums for the supported transports and auth types. ```python theme={"dark"} from xpander_sdk import MCPServerDetails, MCPServerType, MCPServerAuthType server = MCPServerDetails( type=MCPServerType.Remote, name="internal-docs", url="https://mcp.internal.acme.com", auth_type=MCPServerAuthType.APIKey, api_key="...", ) ``` You typically pass a list of these to `Agent.acreate_task(mcp_servers=[...])` to attach servers for a single run; servers configured in the Workbench are added automatically. ### `MCPServerDetails` ```python theme={"dark"} MCPServerDetails( type: MCPServerType = MCPServerType.Remote, name: Optional[str] = None, command: Optional[str] = None, url: Optional[str] = None, transport: MCPServerTransport = MCPServerTransport.HTTP_Transport, auth_type: MCPServerAuthType = MCPServerAuthType._None, api_key: Optional[str] = None, use_secrets_manager: bool = False, client_id: Optional[str] = None, client_secret: Optional[str] = None, headers: Dict = {}, env_vars: Dict = {}, allowed_tools: List[str] = [], additional_scopes: List[str] = [], share_user_token_across_other_agents: bool = True, ) ``` | Field | Type | Description | | -------------------------------------- | -------------------- | -------------------------------------------------------------------------------------------- | | `type` | `MCPServerType` | `Local` (stdio) or `Remote` (HTTP/SSE). | | `name` | `str` | Server name (used in logs and the dashboard). | | `command` | `str` | For `Local` servers: the binary to run. | | `url` | `str` | For `Remote` servers: the server endpoint. | | `transport` | `MCPServerTransport` | `STDIO`, `SSE`, or `HTTP_Transport` (default). | | `auth_type` | `MCPServerAuthType` | `_None`, `APIKey`, `OAuth2`, or `CustomHeaders`. | | `api_key` | `str` | For `APIKey` auth. | | `use_secrets_manager` | `bool` | Resolve the API key from the platform's secrets manager. | | `client_id` / `client_secret` | `str` | For `OAuth2`. | | `headers` | `dict` | Custom headers (used with `CustomHeaders` auth or always-on). | | `env_vars` | `dict` | Env vars to set when launching `Local` servers. | | `allowed_tools` | `list[str]` | Whitelist of tools to expose from this server. Empty = all. | | `additional_scopes` | `list[str]` | Extra OAuth scopes. | | `share_user_token_across_other_agents` | `bool` | When `True`, end users only authenticate once even when multiple agents use the same server. | ### Enums #### `MCPServerType` | Value | Meaning | | --------------------- | ---------------------------------------------------------------------- | | `Local` (`"local"`) | Run a local stdio process. Requires `command` and optional `env_vars`. | | `Remote` (`"remote"`) | Connect to a remote HTTP / SSE server. Requires `url`. | #### `MCPServerTransport` | Value | Meaning | | -------------------------------------- | -------------------------------------------- | | `STDIO` (`"stdio"`) | Standard input/output (Local servers). | | `SSE` (`"sse"`) | Server-sent events. | | `HTTP_Transport` (`"streamable-http"`) | HTTP streaming (default for remote servers). | #### `MCPServerAuthType` | Value | Meaning | | ------------------------------------ | ------------------------------------------------------------------------------ | | `_None` (`"none"`) | No auth. | | `APIKey` (`"api_key"`) | Static API key in `api_key`. | | `OAuth2` (`"oauth2"`) | OAuth2 with `client_id` / `client_secret`. Triggers `auth_event`s during runs. | | `CustomHeaders` (`"custom_headers"`) | Send `headers` as auth. | ### Examples #### Local server (stdio) ```python theme={"dark"} local_server = MCPServerDetails( type=MCPServerType.Local, name="my-local-mcp", command="python -m my_mcp_module", transport=MCPServerTransport.STDIO, env_vars={"DEBUG": "1"}, ) ``` #### Remote with API key ```python theme={"dark"} remote_server = MCPServerDetails( type=MCPServerType.Remote, name="docs-mcp", url="https://mcp.docs.acme.com", transport=MCPServerTransport.HTTP_Transport, auth_type=MCPServerAuthType.APIKey, api_key="sk-...", ) ``` #### Remote with OAuth2 ```python theme={"dark"} oauth_server = MCPServerDetails( type=MCPServerType.Remote, name="github-mcp", url="https://mcp.github.com", auth_type=MCPServerAuthType.OAuth2, client_id="...", client_secret="...", additional_scopes=["repo", "read:user"], ) ``` OAuth2 servers fire `auth_event`s during a run when end-user authorization is required. Register an [`@on_auth_event`](/developers/sdk-reference/decorators#@on_auth_event) handler to route the OAuth URL to your UI. #### Per-task server attachment ```python theme={"dark"} task = await agent.acreate_task( prompt="Search our internal docs for the Q4 roadmap.", mcp_servers=[remote_server], ) ``` These are appended to the agent's persistent MCP config for this task only. #### Limit which tools are exposed ```python theme={"dark"} restricted = MCPServerDetails( type=MCPServerType.Remote, name="github-mcp", url="https://mcp.github.com", auth_type=MCPServerAuthType.OAuth2, client_id="...", client_secret="...", allowed_tools=["search_repositories", "get_issue"], ) ``` Only `search_repositories` and `get_issue` will be exposed to the agent: every other tool the server offers is hidden. ### OAuth response types (for `@on_auth_event` payloads) When OAuth flows fire, `event.data` is shaped like one of these: | Type | Field | Description | | -------------------------- | ---------------------------- | -------------------------- | | `MCPOAuthGetTokenResponse` | `type: MCPOAuthResponseType` | Discriminator. | | | `data: ...` | One of the variants below. | | Variant | Fields | | --------------------------------------- | ---------------------------------- | | `MCPOAuthGetTokenLoginRequiredResponse` | `url`, `server_url`, `server_name` | | `MCPOAuthGetTokenTokenReadyResponse` | `access_token` | | `MCPOAuthGetTokenGenericResponse` | `message` | `MCPOAuthResponseType` values: `not_supported`, `login_required`, `token_issue`, `token_ready`. Use these in your auth handler to display the right state to the end user (login URL vs. "we're working on it" vs. success). # Connect Custom Tools Source: https://docs.xpander.ai/developers/tools/custom-tools Turn a Python function into a tool the agent can call with @register_tool Custom tools are plain Python functions you decorate with `@register_tool` so the agent can call them like any other tool. Use this when: * The connectors catalog doesn't have what you need. * You want to call a private API. * You want the LLM to run logic that already lives in your codebase. ## Prerequisites * **Complete the [Quickstart](/developers/quickstart)** so the CLI, SDK, and `xpander login` are already set up. * **Python 3.12+** for the local handler. * **At least one agent loaded in code** via `Agents().aget(agent_id=...)` or inside an `@on_task` handler. ## 1. Turn a Python function into a tool Write a function with type hints and a docstring, decorate it with `@register_tool`, and make sure the module is imported by your handler. That's all the agent needs to start calling it. ```python xpander_handler.py highlight={3,5} theme={"dark"} from xpander_sdk import register_tool @register_tool def weather_check(location: str) -> str: """Check the current weather for a city.""" return f"Weather in {location}: Sunny, 25C" ``` What this means in practice: 1. **You don't write the schema yourself.** Type hints are the schema. `location: str` becomes a required string parameter; add `= "Paris"` and it becomes optional with a default. 2. **The docstring is the tool's pitch to the LLM.** It's the text the model reads when deciding whether to use this tool, so write it for that audience: what the tool does, what kind of input it expects, what it returns. 3. **The function name becomes the tool name.** The LLM calls it as `weather_check`. Pick names the model can disambiguate from other tools on the agent. 4. **The decorator runs at import time.** As long as the module containing it is imported by your handler, the tool shows up in `agent.tools`. Conditional imports break discovery (the tool will be silently missing) so import the module unconditionally and gate the function's behavior inside its body. 5. **The function stays normal Python.** You can unit-test it, call it from scripts, and refactor it without affecting the agent's other capabilities. ## 2. Use Pydantic for richer input schemas When the LLM benefits from structured input (nested objects, enums, validated fields), use a Pydantic model as the parameter type. The decorator picks up the model and exposes the same field constraints to the LLM that you'd get from a normal Pydantic validator. ```python tools.py highlight={5-8,11} theme={"dark"} from typing import Optional from pydantic import BaseModel from xpander_sdk import register_tool class CustomerFilter(BaseModel): status: str region: Optional[str] = None min_lifetime_value: float = 0.0 @register_tool def search_customers(filter: CustomerFilter, limit: int = 50) -> list[dict]: """Search customers by status, optionally filtered by region and minimum lifetime value.""" # Your implementation goes here. return [] ``` What this means in practice: 1. **The model's fields become a nested object in the tool's schema.** The LLM sees `status` (required), `region` and `min_lifetime_value` (optional with defaults), and supplies them as a structured payload. 2. **The SDK validates the incoming payload before your function runs.** A bad value never reaches your code; the agent gets a `ValueError` it can react to in the next turn. 3. **Anything Pydantic can model, you can use here.** `Optional`, `Union`, `Literal`, `Enum`, field validators. Whatever the model expresses ends up in the schema the LLM sees. ## 3. Make the tool async when it does I/O Most tools that matter make a network call, hit a database, or talk to a queue. Make the function `async def` and the framework awaits it for you. Sync and async tools coexist on the same agent; you pick per tool. ```python highlight={5,7-8} theme={"dark"} import httpx from xpander_sdk import register_tool @register_tool async def fetch_external_data(api_endpoint: str, headers: dict = None) -> dict: """Fetch JSON from an external HTTP endpoint.""" async with httpx.AsyncClient() as client: response = await client.get(api_endpoint, headers=headers or {}) return response.json() ``` What this means in practice: 1. **`async def` is the only difference from a sync tool.** Type hints, docstring, decorator, all the same. 2. **Use async-native clients for the actual I/O.** `httpx.AsyncClient` for HTTP, `asyncpg` or SQLAlchemy 2.x async for Postgres, `aio-pika` for RabbitMQ, etc. A blocking client inside an `async def` blocks the event loop and slows every other tool call running concurrently. 3. **Return the value, don't return the coroutine.** Always `await` the I/O inside the function. If you forget the `await`, the SDK passes the coroutine object back as the tool result and the LLM sees garbage. ## 4. Wire custom tools into your framework Once decorated, the tool joins `agent.tools.list` alongside connectors and any MCP-server tools. You don't write per-framework registration glue: each framework reads the same agent property it already uses for connectors, and your custom tool comes along for the ride. Custom tools are already inside the args dict returned by `Backend.aget_args()`. Just splat the args into Agno's `Agent`: ```python xpander_handler.py highlight={7,15-16} theme={"dark"} from dotenv import load_dotenv load_dotenv() from xpander_sdk import on_task, Task, Backend, register_tool from agno.agent import Agent @register_tool def weather_check(location: str) -> str: """Check the current weather for a city.""" return f"Weather in {location}: Sunny, 25C" @on_task async def handler(task: Task) -> Task: backend = Backend(configuration=task.configuration) # weather_check is already in args["tools"] alongside the connectors. agno_agent = Agent(**(await backend.aget_args(task=task))) result = await agno_agent.arun(input=task.to_message()) task.result = result.content return task ``` Custom tools appear in `agent.openai_agents_sdk_tools` as `FunctionTool` objects, ready for the OpenAI runner: ```python highlight={4,13} theme={"dark"} from xpander_sdk import Agents, register_tool from agents import Agent as OpenAIAgent, Runner @register_tool def weather_check(location: str) -> str: """Check the current weather for a city.""" return f"Weather in {location}: Sunny, 25C" xpander_agent = await Agents().aget(agent_id="agt_01H...") oa_agent = OpenAIAgent( name=xpander_agent.name, instructions=xpander_agent.instructions.full, tools=xpander_agent.openai_agents_sdk_tools, # connectors + weather_check model=xpander_agent.model_name, ) result = await Runner.run(oa_agent, input="Weather in Paris?") ``` Custom tools appear in `agent.tools.functions` as plain Python callables. Pass them straight to `create_react_agent`: ```python highlight={5,13} theme={"dark"} from xpander_sdk import Agents, register_tool from langchain_openai import ChatOpenAI from langgraph.prebuilt import create_react_agent @register_tool def weather_check(location: str) -> str: """Check the current weather for a city.""" return f"Weather in {location}: Sunny, 25C" xpander_agent = await Agents().aget(agent_id="agt_01H...") react = create_react_agent( model=ChatOpenAI(model=xpander_agent.model_name), tools=xpander_agent.tools.functions, # connectors + weather_check state_modifier=xpander_agent.instructions.full, ) ``` Custom tools appear in `agent.strands_tools`. Pass the list to Strands' `Agent`: ```python highlight={4,13} theme={"dark"} from xpander_sdk import Agents, register_tool from strands.agent import Agent as StrandsAgent @register_tool def weather_check(location: str) -> str: """Check the current weather for a city.""" return f"Weather in {location}: Sunny, 25C" xpander_agent = await Agents().aget(agent_id="agt_01H...") strands_agent = StrandsAgent( name=xpander_agent.name, system_prompt=xpander_agent.instructions.full, tools=xpander_agent.strands_tools, # connectors + weather_check model=xpander_agent.model_name, ) ``` The decorator emits one tool definition; each per-framework property wraps it in the shape that framework expects. ## 5. Make a tool selectively available `@register_tool` adds a tool to the agent's permanent capability set: every task gets it. If you only want a tool available for a single call (a debug helper, a test stub, a per-request override), skip the decorator and pass it through `Backend.aget_args(tools=[...])` instead. The tool gets appended to the resolved tools list for that one call only. The agent's permanent capability set stays untouched: ```python highlight={6-8,12} theme={"dark"} from datetime import datetime from xpander_sdk import Backend backend = Backend(configuration=task.configuration) def _local_clock() -> str: """Return the developer's local clock for debugging.""" return datetime.now().isoformat() args = await backend.aget_args( task=task, tools=[_local_clock], # appended to connectors + @register_tool functions ) ``` Reach for `@register_tool` when a tool belongs to the agent for good. Reach for `tools=[...]` when it's situational. ## 6. Inspect and invoke custom tools directly Custom tools are queryable through the same APIs as connectors. Reach for these when you want to sanity-check that your decorator picked them up, build a UI showing the agent's full surface, or invoke a tool by hand outside the LLM loop. ```python theme={"dark"} from xpander_sdk import Agents agent = await Agents().aget(agent_id="agt_01H...") # Every tool on the agent: connectors + @register_tool functions + MCP tools. for tool in agent.tools.list: kind = "local" if tool.is_local else "connector" print(tool.name, kind, tool.description[:60]) # Look up a single custom tool and invoke it directly. weather_tool = agent.tools.get_tool_by_name("weather_check") result = await agent.ainvoke_tool( tool=weather_tool, payload={"location": "Paris"}, ) print(result.is_success, result.result) ``` What this means in practice: 1. **Custom tools and connectors look the same to the platform.** They share `agent.tools.list`, the same lookup helpers, and the same `ainvoke_tool` entry point. `tool.is_local` distinguishes the two when you need to. 2. **Direct invocation skips the LLM.** Useful for migration scripts, batch jobs, or testing the tool's contract before exposing it to the model. 3. **The payload structure follows the schema you declared.** For a tool typed with primitives, the payload is the keyword args dict. For a Pydantic-typed parameter, the payload is the model's serialized form. | Property | Returns | What it's for | | ----------------------------------------------------------- | ---------------- | ---------------------------------------------------------------------------------------------------------------------------------------------- | | `agent.tools.list` | `list[Tool]` | Canonical enumeration. Each `Tool` carries `id`, `name`, `description`, `parameters` (JSON schema), `is_local`, and a Pydantic `schema`. | | `agent.tools.functions` | `list[Callable]` | Normalized callables for every tool with a `payload: ` parameter. Bind into LangChain or any "plain Python function" framework. | | `agent.tools.get_tool_by_name(name)` / `get_tool_by_id(id)` | `Tool` | Look up a single tool. `id` and `name` are equal for `@register_tool` functions (both default to the function's `__name__`). | ## 7. Register custom tools with the platform By default, a registered tool only exists inside your handler process. The framework can call it because it's in the local registry, but the platform's record of the agent doesn't list it. It won't appear in Agent Studio's Tools tab, and you can't reference it in dependency rules. To register the tool with the platform too, pass `add_to_graph=True`: ```python highlight={1} theme={"dark"} @register_tool(add_to_graph=True) async def lookup_internal_ticket(ticket_id: str) -> dict: """Look up an internal support ticket by ID.""" ... ``` What this means in practice: 1. **Code changes need a new rollout of your handler.** Adding, editing, or removing a `@register_tool` function changes the code. Control-plane changes (instructions, model, attached connectors) stay live without one. 2. **`add_to_graph=True` syncs on agent load, not on deploy.** The first task after rollout triggers the platform sync; the deploy itself doesn't. The flag is idempotent. Subsequent loads skip already-synced tools, so you can leave it set permanently. 3. **Leave `add_to_graph` off when you don't need platform-side features.** The LLM doesn't need it to call the tool, and skipping it keeps Agent Studio's view scoped to platform-managed configuration. ## Troubleshooting The decorator runs at import time. If the module that holds the tool is never imported (because the handler has a conditional import, or because the tool lives in a file the handler doesn't reference), the decorator never executes and the tool is invisible. Move the `@register_tool` function into a module the handler imports unconditionally, or add an explicit `from .tools import *` to your handler's top imports. Schema generation reads type hints, not runtime values. A parameter typed as `dict` produces a generic object schema with no field constraints; the LLM will fill it with whatever it thinks is reasonable. To get a strict schema, model the parameter with a Pydantic `BaseModel` (Section 2). For unions and enums, use `typing.Union` and `enum.Enum` so Pydantic emits the right schema fragments. Untyped parameters fall back to `Any`, which produces a permissive schema and often leads to runtime errors when the LLM passes the wrong type. Annotate every parameter. If you really need a free-form value, use `typing.Any` explicitly so future readers know it was a deliberate choice. The framework awaits coroutines automatically, but only if the function itself is `async def`. If you write `def run(...): return some_coroutine()` instead of `async def run(...)`, the SDK passes the coroutine object back as the tool result and the LLM gets garbage. Make the function `async def` and `await` inside it. The graph sync runs in the background the next time the agent is loaded with `Agents().aget(agent_id=...)`. If you only ever call `Backend.aget_args(task=task)` inside an `@on_task` handler, the agent is loaded each task and the sync fires there too. Force a sync from a script: load the agent, wait a couple of seconds for the background task, then refresh the Tools tab in [Agent Studio](https://chat.xpander.ai). Output schema filtering applies to remote connector calls, not to `@register_tool` functions. Whatever your function returns reaches the LLM verbatim. To shrink local-tool output, project to the fields you want before returning, or wrap the call in a [tool hook](/developers/tools/tool-hooks) that rewrites the response. ## Next steps The other half of `agent.tools.list`. Slack, Gmail, GitHub, and 2,000+ more. Observe, log, and rewrite every tool call across the agent's lifetime. How large tool responses get filtered before reaching the LLM. How `agent.tools.functions`, `openai_agents_sdk_tools`, and `strands_tools` map onto each framework. A standalone runnable script that wires `@register_tool` end to end. # Output Response Filtering Source: https://docs.xpander.ai/developers/tools/output-response-filtering Handle any size tool response without overflowing the context window Output response filtering lets xpander agents handle tool responses of any size without overflowing the context window. A tool or connector might return a 50KB JSON response, which is mostly noise. You configure a per-tool output schema once in [Agent Studio](https://chat.xpander.ai), and xpander trims the response down to the fields you whitelist before it reaches your framework. ## Configure an output schema Open your agent in [Agent Studio](https://chat.xpander.ai) and go to the **Tools** tab. You'll see your attached connectors listed under **Tools**. Tools tab showing attached connectors Click the edit icon next to the tool you want to filter. In the dialog, select the **Output schema** tab. Declare the fields you want the agent to see. Anything you omit is dropped before the response reaches the LLM. Output schema tab on a connector tool Write the schema from a real captured response, not the API docs. Open the agent's run history, expand a tool result to see the full JSON shape, and pick only the fields the agent actually needs to answer questions. Be aggressive. Leave a field out and add it back only if the agent fails without it. Click **Save**, then **Deploy changes** at the top of the Builder. The schema applies to every invocation from that point on, across all frameworks. ## Verify the filtered shape from code Once a schema is published, invoke the tool directly and inspect what the LLM actually receives: ```python theme={"dark"} from xpander_sdk import Agents agent = await Agents().aget(agent_id="agt_01H...") tool = agent.tools.get_tool_by_name("SalesforceQueryAccounts") result = await agent.ainvoke_tool( tool=tool, payload={"body_params": {"q": "SELECT Id, Name FROM Account"}}, ) print(result.result) # Already filtered by the configured output schema. ``` To confirm what was removed, briefly clear the schema in Agent Studio, capture the full response, then re-enable it. The diff is exactly what you've cut from the LLM's context. ## Troubleshooting Output response filtering only applies to remote connector calls, not local `@register_tool` functions. Whatever you return from a Python function reaches the LLM verbatim. To slim local-tool output, do it inside the function before returning. The schema dropped a field the agent actually needed. Add it back and republish. Common case: stripping `created_at` because it seems unnecessary, then a user asks "when did we onboard them?" and the agent guesses. Output schemas are allow-lists. If the upstream API adds a field, your schema silently drops it. When a connector announces an API update, re-check your schemas against a fresh captured response. Either no schema is configured, the tool you filtered isn't the one driving most tokens, or the response was already small. Use the run history to find which tool calls return the largest payloads and filter those first. List endpoints and search results are usually the biggest wins. ## Next steps The full reference for connector tools, including the input-schema half of the Advanced tab. Observe and log tool calls, including filtered responses, across the agent's lifetime. Add your own Python functions with `@register_tool`. Output filtering does not apply to local tools. Indexed retrieval for grounding agents in your own corpus. # Use Pre-built Connectors Source: https://docs.xpander.ai/developers/tools/pre-built How connectors selected in Agent Studio show up as tools in code, and how to invoke them xpander.ai ships 2,000+ pre-built connectors (Slack, Gmail, GitHub, Salesforce, and more). You select which ones an agent can use in [Agent Studio](https://chat.xpander.ai); the SDK then exposes them as ready-to-call functions on the loaded `Agent`. No manual fetching, no schema conversion, no client setup. ## Prerequisites * **Complete the [Quickstart](/developers/quickstart)** so the CLI, SDK, and `xpander login` are already set up. * **Python 3.12+** for the local handler. ## 1. Set up connectors in Agent Studio Setup is a one-time UI flow: pick a connector, authenticate, attach the actions you want to your agent. Once published, the connector's actions are live on every loaded `Agent` instance and reachable from any framework you bind them into. Pick a connector, authenticate, attach actions to your agent. Browsing connectors in Agent Studio Everything below assumes you've done this and your agent has at least one connector attached. ## 2. List all available tools Once a connector is attached, your agent has access to three types of tools: * **Connector tools**: every action you selected from a pre-built connector (Slack, Gmail, GitHub, etc.) * **Custom tools**: Python functions you decorated with `@register_tool` * **MCP tools**: tools from any MCP server you've attached Use `agent.tools.list` to enumerate all of them: ```python theme={"dark"} from xpander_sdk import Agents agent = await Agents().aget(agent_id="agt_01H...") # Every tool the agent can call, mixed sources for tool in agent.tools.list: print(tool.name, tool.is_local, tool.description[:80]) ``` This is what you'd use to: * Build a UI that shows the user which capabilities an agent has before they prompt it. * Sanity-check after a publish that the connector you just attached actually shows up. * Filter the tool list at runtime (e.g. drop write-actions when running in a read-only context). ### Inspect individual tools If you want to inspect the exact shape that's about to be handed to the framework (debugging "are my FunctionTools correct?", "did the LangChain callables get their docstrings?"), enumerate the framework-specific list instead: The args dict from `Backend.aget_args()` carries the resolved tools list. Iterate `args["tools"]` to see exactly what Agno will receive: ```python theme={"dark"} from xpander_sdk import Backend backend = Backend() args = await backend.aget_args(agent_id="agt_01H...", task=task) for tool in args["tools"]: print(tool.__name__, tool.__doc__[:80] if tool.__doc__ else "") ``` `agent.openai_agents_sdk_tools` returns `FunctionTool` objects ready for the OpenAI runner: ```python theme={"dark"} from xpander_sdk import Agents xpander_agent = await Agents().aget(agent_id="agt_01H...") for tool in xpander_agent.openai_agents_sdk_tools: # FunctionTool exposes .name and .description print(tool.name, tool.description[:80]) ``` `agent.tools.functions` returns plain Python callables with `payload: ` parameters and LLM-friendly docstrings: ```python theme={"dark"} from xpander_sdk import Agents xpander_agent = await Agents().aget(agent_id="agt_01H...") for fn in xpander_agent.tools.functions: print(fn.__name__, (fn.__doc__ or "")[:80]) ``` `agent.strands_tools` returns the list ready for Strands' `tools=` arg: ```python theme={"dark"} from xpander_sdk import Agents xpander_agent = await Agents().aget(agent_id="agt_01H...") for tool in xpander_agent.strands_tools: print(tool.__name__, (tool.__doc__ or "")[:80]) ``` Three properties you'll reach for most often: | Property | Returns | What it's for | | ----------------------------------------------------------- | ---------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `agent.tools.list` | `list[Tool]` | Canonical enumeration. Each `Tool` carries `id`, `name`, `description`, `parameters` (raw JSON schema), and a Pydantic `schema`. | | `agent.tools.functions` | `list[Callable]` | Normalized callables, one per tool, with a `payload: ` parameter and an LLM-friendly docstring. Bind them straight into LangChain, OpenAI Agents SDK, or any "plain Python function" framework. | | `agent.tools.get_tool_by_id(id)` / `get_tool_by_name(name)` | `Tool` | Look up a single tool when you want to invoke it by hand. | ## 3. Bind tools into the framework Listing tools tells you what the agent can do. Binding them is what gets the LLM to actually call them. Every framework wants tools in its own shape, and the xpander Agent exposes one property per supported framework, computed off the same underlying tool list: ```python xpander_handler.py highlight={10,12} theme={"dark"} from dotenv import load_dotenv load_dotenv() from xpander_sdk import on_task, Task, Backend from agno.agent import Agent @on_task async def handler(task: Task) -> Task: backend = Backend(configuration=task.configuration) agno_args = await backend.aget_args(task=task) agno_agent = Agent(**agno_args) result = await agno_agent.arun( input=task.to_message(), files=task.get_files(), images=task.get_images(), ) task.result = result.content return task ``` See the [Agno page](/developers/frameworks/agno) for the full walkthrough. ```python xpander_handler.py highlight={16} theme={"dark"} from dotenv import load_dotenv load_dotenv() from xpander_sdk import on_task, Task, Agents from agents import Agent as OpenAIAgent, Runner @on_task async def handler(task: Task) -> Task: xpander_agent = await Agents(configuration=task.configuration).aget( agent_id=task.agent_id ) oa_agent = OpenAIAgent( name=xpander_agent.name, instructions=xpander_agent.instructions.full, tools=xpander_agent.openai_agents_sdk_tools, model=xpander_agent.model_name, ) result = await Runner.run(oa_agent, input=task.to_message()) task.result = result.final_output return task ``` See the [OpenAI Agents SDK page](/developers/frameworks/openai-agents) for the full walkthrough. ```python xpander_handler.py highlight={16} theme={"dark"} from dotenv import load_dotenv load_dotenv() from xpander_sdk import on_task, Task, Agents from langchain_openai import ChatOpenAI from langgraph.prebuilt import create_react_agent @on_task async def handler(task: Task) -> Task: xpander_agent = await Agents(configuration=task.configuration).aget( agent_id=task.agent_id ) react = create_react_agent( model=ChatOpenAI(model=xpander_agent.model_name), tools=xpander_agent.tools.functions, state_modifier=xpander_agent.instructions.full, ) response = await react.ainvoke({ "messages": [("user", task.to_message())], }) task.result = response["messages"][-1].content return task ``` See the [LangChain page](/developers/frameworks/langchain) for the full walkthrough. ```python xpander_handler.py highlight={16} theme={"dark"} from dotenv import load_dotenv load_dotenv() from xpander_sdk import on_task, Task, Agents from strands.agent import Agent as StrandsAgent @on_task async def handler(task: Task) -> Task: xpander_agent = await Agents(configuration=task.configuration).aget( agent_id=task.agent_id ) strands_agent = StrandsAgent( name=xpander_agent.name, system_prompt=xpander_agent.instructions.full, tools=xpander_agent.strands_tools, model=xpander_agent.model_name, ) result = await strands_agent.ainvoke_async(task.to_message()) task.result = str(result) return task ``` See the [AWS Strands page](/developers/frameworks/aws-strands) for the full walkthrough. ## 4. Invoke a tool yourself (optional) Most of the time the framework decides when to call a connector. But you can also reach in and call one directly. Use this to: * Run an admin or migration script that calls a connector once (send a Slack announcement, archive a Salesforce record) without standing up a full agent loop. * Backfill or batch-process by iterating over a queue of inputs and firing the same tool against each. * Test a connector's payload shape end-to-end before exposing it to the LLM. ```python theme={"dark"} from xpander_sdk import Agents agent = await Agents().aget(agent_id="agt_01H...") email_tool = agent.tools.get_tool_by_id( "XpanderEmailServiceSendEmailWithHtmlOrTextContent" ) result = await agent.ainvoke_tool( tool=email_tool, payload={ "body_params": { "subject": "Hello from xpander", "body_html": "

Hi there!

", "to": ["recipient@example.com"], }, "path_params": {}, "query_params": {}, }, ) print(result.is_success, result.result) ``` What this means in practice: 1. **`agent.tools.get_tool_by_id(...)`** looks up the connector tool by its stable identifier. Use `get_tool_by_name(...)` if you have the human-readable name instead. 2. **The `payload` mirrors the tool's JSON schema.** Connector tools typically have `body_params`, `path_params`, and `query_params` as the top-level keys, mapping to the underlying API's request shape. Inspect `tool.parameters` if you need the schema. 3. **`ToolInvocationResult`** comes back with `is_success` (bool) and `result` (the raw response). Check `is_success` before consuming `result`. The sync form `agent.invoke_tool(...)` exists with the same signature. ## 5. Pass per-request context to every tool call When the same agent definition serves many tenants, customers, or users, you usually need to stamp something onto every connector call (a tenant ID, a customer ID, a request ID, an OAuth token override) without putting it in the prompt or hardcoding it on the agent. That's what `tool_call_payload_extension` is for. It deep-merges into every tool call's payload for the lifetime of the task: ```python theme={"dark"} task = await agent.acreate_task( prompt="Summarize this customer's recent activity", # Every connector call inside this task gets tenant_id merged into body_params. tool_call_payload_extension={"body_params": {"tenant_id": "acme-corp"}}, ) ``` Common shapes: * **Multi-tenant**: stamp the tenant ID on every downstream call so connector requests scope correctly. * **Per-user OAuth**: pass a user-scoped token override into `body_params` or a custom auth header. * **Traceability**: add a request ID to every connector call so you can follow a single user's actions across systems. The same dict surface is accepted on three call sites, scoped differently: | Where you pass it | Argument | Scope | When to use | | ---------------------------- | ---------------------------------------------------- | ----------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------- | | `agent.acreate_task(...)` | `tool_call_payload_extension: Optional[dict] = None` | Every tool call inside the task. | The default. Stamping context that's the same for the whole task (tenant ID, request ID, user token). | | `Backend.ainvoke_agent(...)` | `tool_call_payload_extension: Optional[dict] = None` | Every tool call inside the task implicitly created by the invoke. | When you're invoking an agent through `Backend` rather than creating a task explicitly. | | `agent.ainvoke_tool(...)` | `payload_extension: Optional[Dict] = {}` | One tool invocation. | Reaching past the LLM to call a specific tool by hand and you only want to stamp this call. | The merge is deep, not shallow. Mirror the tool's payload shape (`body_params`, `path_params`, `query_params`) when extending, otherwise the keys land at the wrong level and the connector ignores them. ## Troubleshooting The agent has no connectors attached, or the connectors you attached aren't published yet. Open the agent in [Agent Studio](https://chat.xpander.ai), check the **Tools** tab for at least one entry, and click **Publish** if you see a "Deploy changes" banner. Then reload the agent: `agent = await Agents().aget(agent_id=...)`. The payload doesn't match the connector's expected shape. Inspect `tool.parameters` (raw JSON schema) and confirm `body_params`, `path_params`, and `query_params` line up with the underlying API. The Pydantic `tool.schema` is also useful for type-checking the payload before sending. The extension is deep-merged, so it only adds keys at the same path. If you pass `{"body_params": {"tenant_id": "..."}}`, it merges into the tool's `body_params`; it won't appear in `query_params`. Mirror the tool's payload structure when extending. ## Next steps Add your own Python functions alongside connectors with `@register_tool`. Observe, log, and rewrite every tool call across the agent's lifetime. How large tool responses get filtered before reaching the LLM. Browse all 2,000+ pre-built integrations. The UI walkthrough: connections, OAuth, attaching actions. How `agent.tools.functions`, `openai_agents_sdk_tools`, and `strands_tools` map onto each framework. # Observability with Tool Hooks Source: https://docs.xpander.ai/developers/tools/tool-hooks Observe and instrument every tool call without modifying the tools themselves Tool hooks are decorators that fire around every tool invocation an agent makes. They give you a single place to plug in logging, metrics, alerting, payload redaction, custom guardrails, and per-tool observability without touching the tools themselves. Hooks are framework-agnostic: they run at the SDK level, so the same hook fires whether the agent is built on Agno, OpenAI Agents SDK, LangChain, or AWS Strands, and whether the tool is a connector, a custom `@register_tool` function, or an MCP-server tool. There are three decorators: * `@on_tool_before` runs before each tool invocation. * `@on_tool_after` runs after a successful invocation, with the result. * `@on_tool_error` runs when a tool invocation raises. ## Prerequisites * **Complete the [Quickstart](/developers/quickstart)** so the CLI, SDK, and `xpander login` are already set up. * **An agent with at least one tool attached.** Connectors selected in [Agent Studio](https://chat.xpander.ai), `@register_tool` functions, or MCP-server tools all work. * **Python 3.12+** for the local handler. ## 1. Log every tool call The smallest useful hook is a logger that records each tool the agent reaches for. Drop the three decorators in a module that's imported from your handler and they auto-register at import time: ```python hooks.py highlight={5,12,20} theme={"dark"} from typing import Any, Dict, Optional from loguru import logger from xpander_sdk import on_tool_before, on_tool_after, on_tool_error, Tool @on_tool_before def log_invocation(tool: Tool, payload: Any, payload_extension: Optional[Dict[str, Any]] = None, tool_call_id: Optional[str] = None, agent_version: Optional[str] = None): logger.info(f"-> {tool.name} called with payload {payload}") @on_tool_after def log_success(tool: Tool, payload: Any, payload_extension: Optional[Dict[str, Any]] = None, tool_call_id: Optional[str] = None, agent_version: Optional[str] = None, result: Any = None): logger.info(f"<- {tool.name} returned {type(result).__name__}") @on_tool_error def log_failure(tool: Tool, payload: Any, payload_extension: Optional[Dict[str, Any]] = None, tool_call_id: Optional[str] = None, agent_version: Optional[str] = None, error: Optional[Exception] = None): logger.error(f"x {tool.name} failed: {error}") ``` What this means in practice: 1. **`@on_tool_before`** runs immediately before the tool body executes. The `Tool` object exposes `tool.name`, `tool.id`, `tool.is_local` (true for `@register_tool` functions, false for connectors), and `tool.description`. 2. **`@on_tool_after`** only runs on success and adds a `result` parameter carrying whatever the tool returned. For connector tools, that's the raw response body. For local tools, it's whatever your function returned. 3. **`@on_tool_error`** runs in place of the after-hook when the tool raises. The `error` parameter is the original exception. The agent's framework still sees the failure; the hook is for your side effects (logs, alerts, traces). 4. **`tool_call_id`** is unique per invocation. Use it as the correlation key to pair before-hooks with their matching after-hooks or error-hooks. 5. **Both sync and async hooks work.** The SDK detects coroutine functions and awaits them automatically, so you can `await` an HTTP client or a DB write inside an async hook without extra wiring. Three traits of every hook signature, regardless of which decorator you use: | Parameter | Type | Notes | | --------------------- | --------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `tool` | `Tool` | The tool being invoked. Read `tool.name`, `tool.id`, `tool.is_local`, `tool.description`. Always set. | | `payload` | `Any` | The arguments the LLM produced for the call. For connectors, typically `{"body_params": {...}, "path_params": {...}, "query_params": {...}}`. For local tools, whatever your function expects. Always set. | | `payload_extension` | `Optional[Dict]` | The deep-merged extension you passed via `tool_call_payload_extension` on the task or `payload_extension=` on `agent.ainvoke_tool`. `None` if you didn't set one. | | `tool_call_id` | `Optional[str]` | Stable identifier for one invocation. Pair before/after hooks with this key. | | `agent_version` | `Optional[str]` | The deployed version of the agent that issued the call. Useful for filtering metrics by rollout. | | `result` (after only) | `Any` | The value the tool returned on success. | | `error` (error only) | `Optional[Exception]` | The exception raised by the tool body. | ## 2. Time and instrument every tool call Once you have logging, the next thing most teams want is timing and counter metrics per tool. The before/after pair is the natural fit, with `tool_call_id` as the correlation key: ```python hooks.py highlight={5,7,15} theme={"dark"} import time from typing import Any, Dict, Optional from xpander_sdk import on_tool_before, on_tool_after, Tool starts: dict[str, float] = {} @on_tool_before def record_start(tool: Tool, payload: Any, payload_extension: Optional[Dict[str, Any]] = None, tool_call_id: Optional[str] = None, agent_version: Optional[str] = None): if tool_call_id: starts[tool_call_id] = time.time() @on_tool_after def record_duration(tool: Tool, payload: Any, payload_extension: Optional[Dict[str, Any]] = None, tool_call_id: Optional[str] = None, agent_version: Optional[str] = None, result: Any = None): started = starts.pop(tool_call_id, None) if tool_call_id else None if started is not None: metrics_client.timing(f"tool.{tool.name}.duration_ms", (time.time() - started) * 1000) metrics_client.increment(f"tool.{tool.name}.calls") ``` What this means in practice: 1. **`tool_call_id` is the correlation key.** Concurrent tool calls run on the same agent, so a global timestamp would clobber. The id stays stable from the before hook to the matching after or error hook. 2. **Pop, don't peek.** Removing the entry on the after hook keeps memory bounded across long-running processes. 3. **Embed `tool.name` in the metric name.** Per-tool dashboards drop out of this naming scheme without per-tool boilerplate. Mirror the increment in `@on_tool_error` so success and failure counters add up to the total call count. ## 3. Redact payloads and add custom guardrails Hooks are observe-only by design. The SDK calls them, but ignores any return value, so you cannot mutate the payload or rewrite the result from a hook. What you can do is: * **Redact at the sink.** Strip secrets from the copy of the payload you log or send to a tracing backend. * **Detect and alert.** Match the payload against a guardrail policy and emit an alert or a metric when it trips. * **Raise to fail loud.** A hook that raises has its exception logged by the SDK; the tool itself still runs, but the alert reaches your error-tracking system. ```python hooks.py highlight={5,12-13,15-17} theme={"dark"} import copy from typing import Any, Dict, Optional from xpander_sdk import on_tool_before, Tool SENSITIVE_KEYS = {"api_key", "password", "ssn", "credit_card"} @on_tool_before def redact_and_log(tool: Tool, payload: Any, payload_extension: Optional[Dict[str, Any]] = None, tool_call_id: Optional[str] = None, agent_version: Optional[str] = None): # Deep copy so we never touch the live payload the tool will receive. safe = copy.deepcopy(payload) if isinstance(payload, dict) else payload if isinstance(safe, dict): for key in list(safe.get("body_params", {})): if key.lower() in SENSITIVE_KEYS: safe["body_params"][key] = "***" audit_log.write({"tool": tool.name, "tool_call_id": tool_call_id, "payload": safe}) ``` What this means in practice: 1. **`copy.deepcopy(payload)`** is the safety net. Even though hook return values are ignored, mutating a shared dict in place could affect other observers reading the same object. Copy first, redact the copy. 2. **`SENSITIVE_KEYS`** is your project's policy. Extend it with whatever your security team flags. 3. **`audit_log.write(...)`** is a stand-in for whatever sink you ship to (S3, Datadog, OpenTelemetry). Hooks are the right place for this work because they fire on every tool, not just the ones you remember to instrument. To enforce a policy that should *block* a call, do it inside the tool function itself. Hooks fire before the tool body runs, but raising from a hook only logs the exception, it doesn't cancel the invocation. ## 4. Alert on failures of business-critical tools Most tool errors are noise: an LLM produced an invalid payload, a connector returned a 4xx, the agent retries. The few that should page someone (a charge that didn't go through, an auth check that broke) deserve their own hook with a name allowlist: ```python hooks.py highlight={3,8-9} theme={"dark"} from xpander_sdk import on_tool_error, Tool CRITICAL = {"payment_processor", "auth_service", "fraud_check"} @on_tool_error async def alert_on_failure(tool: Tool, payload, payload_extension=None, tool_call_id=None, agent_version=None, error=None): if tool.name not in CRITICAL: return await alert_service.send( title=f"Critical tool failure: {tool.name}", message=f"Error: {error}\nCall ID: {tool_call_id}\nAgent: {agent_version}", severity="critical", ) ``` What this means in practice: 1. **The name allowlist** is what keeps alert volume sane. Without it, every transient connector failure pages you. 2. **`agent_version`** is included in the alert so you can correlate a spike of errors with the rollout that introduced it. 3. **The hook is async**, so it can `await` an HTTP call to PagerDuty or Slack without spinning up a background thread. ## 5. Attribute cost and usage per tenant Tool hooks are how you build per-customer billing or per-team cost dashboards on top of agent activity. Combine [`tool_call_payload_extension`](/developers/tools/pre-built#5-pass-per-request-context-to-every-tool-call) with an `@on_tool_after` hook that reads the tenant ID off the extension and increments a counter: ```python hooks.py theme={"dark"} from xpander_sdk import on_tool_after, Tool @on_tool_after async def attribute_cost(tool: Tool, payload, payload_extension=None, tool_call_id=None, agent_version=None, result=None): tenant_id = (payload_extension or {}).get("body_params", {}).get("tenant_id") if tenant_id: await billing.increment(tenant_id, tool=tool.name, count=1) ``` What this means in practice: 1. **`payload_extension`** is the same dict you set when creating the task with `tool_call_payload_extension={"body_params": {"tenant_id": "acme-corp"}}`. Every tool call inside that task carries it through to the hook. 2. **The hook fires on every successful invocation**, so the counter reflects real usage, not LLM intentions. 3. **It works uniformly across tool types.** Connector calls, custom `@register_tool` calls, and MCP tools all hit this hook with the same extension. ## 6. Where hooks fit in your project Register hooks at module level so they're set up before any task is processed. The cleanest pattern is a `hooks.py` imported from your handler: ```python xpander_handler.py highlight={1} theme={"dark"} import hooks # registers logging, metrics, and audit hooks at import time from xpander_sdk import on_task, Task, Backend from agno.agent import Agent @on_task async def handler(task: Task) -> Task: backend = Backend(configuration=task.configuration) agno_agent = Agent(**(await backend.aget_args(task=task))) result = await agno_agent.arun(input=task.to_message()) task.result = result.content return task ``` What this means in practice: 1. **The `import hooks` line is enough.** Each `@on_tool_before` / `@on_tool_after` / `@on_tool_error` decorator registers itself in a process-global registry on import. There's no `register_hooks(...)` call. 2. **Hooks compose with `@on_boot`.** Use a boot handler to construct the metrics client, alerting client, or audit-log writer that your hooks reach for, so they exist before the first tool fires. 3. **Hooks coexist with framework-level callbacks.** Agno's `tool_hooks` arg, OpenAI Agents SDK's run hooks, and LangChain callbacks all keep working. xpander's hooks fire at the SDK's tool-invocation layer, so they run alongside (not instead of) any framework callback you've already wired up. ## How hooks fire The SDK runs hooks synchronously around the tool body. The order is fixed: 1. Schema validation runs first if the tool has a Pydantic schema. 2. All `@on_tool_before` hooks run, in registration order. 3. The tool body executes (the connector HTTP call, the local `@register_tool` function, or the MCP server call). 4. **On success**, every `@on_tool_after` hook runs, in registration order, with the result. 5. **On failure**, every `@on_tool_error` hook runs, in registration order, with the exception. 6. Activity reporting to Agent Studio happens after hooks return, so your hooks see the call before the platform's metrics view does. A few non-obvious properties: * **Exceptions inside a hook are caught by the SDK and logged.** They don't prevent the tool from running, don't cancel sibling hooks, and don't propagate to the agent loop. This makes hooks safe for instrumentation, but it means you can't use them to block a call. * **Hooks observe; they don't mutate.** The SDK calls each hook and ignores its return value. Mutate the local copy you log, but don't expect hook returns to alter the live payload or rewrite the result. * **Order matters when hooks share state.** If two `@on_tool_after` hooks both read a dict populated by a `@on_tool_before` hook, register them in the order the after-hooks need to run. ## Troubleshooting The decorator only registers the hook when the module that defines it is imported. If `hooks.py` lives next to `xpander_handler.py` but nothing ever imports it, the decorators never run. Add `import hooks` at the top of `xpander_handler.py` (or wherever your `@on_task` lives) so registration happens at boot. Hooks register globally, so importing `hooks.py` from two different modules registers each decorator twice. Pick one import site (the handler) and remove the others. Re-running `xpander agent dev` reloads the registry from a fresh process, which is the easiest way to confirm. The SDK detects coroutine functions and awaits them; sync hooks run inline. If you wrote a sync hook that calls `asyncio.run(...)` or blocks on a sync HTTP client inside an async handler, you'll stall the event loop. Either declare the hook `async def` and `await` an async client, or keep it sync and use a non-blocking client. Hook exceptions are caught and logged by the SDK; the tool still runs. If you need a hook failure to be loud, push the exception to your error tracker yourself (`sentry_sdk.capture_exception(e)`) inside a `try/except`. Don't rely on the exception bubbling up to the agent loop, because it won't. `tool_call_payload_extension` is a per-task setting passed to `agent.acreate_task(...)`. If you're invoking a tool by hand with `agent.ainvoke_tool(...)` and didn't pass `payload_extension=...`, the hook receives `None`. Either set the extension on the task, or pass it to `ainvoke_tool` directly. It is. Hooks observe the call; they don't mutate it. The SDK ignores whatever a hook returns. To shape the payload that reaches a tool, use input schema overrides on the tool's Advanced tab in [Agent Studio](https://chat.xpander.ai). To shape the result the LLM sees, use [Output Response Filtering](/developers/tools/output-response-filtering) or filter inside your `@register_tool` function before returning. ## Next steps The other tool surface hooks observe, including `tool_call_payload_extension` for per-tenant context. Wrap your own Python functions with `@register_tool`. Hooks fire for these too. How large tool responses get filtered before reaching the LLM. `@on_boot` and `@on_shutdown` for setting up the clients your tool hooks reach for. How tool calls flow through Agno, OpenAI Agents SDK, LangChain, and AWS Strands. The SDK class names mapped onto agents, tasks, threads, and tools. # Multi-Agent Tasks Source: https://docs.xpander.ai/guides/agentic-automation/multi-agent-tasks Attach specialized agents to a coordinator so they can delegate tasks to each other during conversations. Instead of building one agent with every connector and a massive system prompt, split the work across specialized agents. A coordinator agent talks to the user and delegates to specialists as needed. ```text theme={"dark"} User │ ▼ ┌─────────────┐ │ Coordinator │ ← talks to the user, decides who to call └──────┬──────┘ │ ┌─────┼──────┐ ▼ ▼ ▼ ┌─────┐ ┌────┐ ┌─────┐ │ CRM │ │Jira│ │Slack│ ← specialists with scoped tools └─────┘ └────┘ └─────┘ ``` **Multi-agent vs. workflows:** Multi-agent is for conversations where a user asks a question and agents collaborate to answer. Workflows are for backend automation triggered by events with no user in the loop. ## Attach agents to enable delegation Open any agent's **General** tab and scroll to **Multi-Agent**. Click **Attach agents** to open a searchable panel listing every agent in your workspace. When you attach Agent B to Agent A, Agent B appears as a callable tool in Agent A's tool list. The coordinator doesn't need to know how to query Salesforce directly. It just calls the Salesforce specialist tool, which runs that agent with the delegated task and returns the result. ## Set up a coordinator **1. Build specialists first.** Each one gets its own system prompt, connectors, and knowledge base scoped to one domain. You'll see them listed on the Agents page alongside your other agents. Agents list page **2. Build the coordinator.** Go to the **Instructions** tab and write a system prompt that describes when to delegate: Agent Instructions tab with delegation prompt ```text theme={"dark"} You are a support triage agent. When a user asks about: - Sales pipeline or deal status: delegate to the Salesforce agent - Open tickets or project status: delegate to the Jira agent - Recent conversations or mentions: delegate to the Slack agent Synthesize results from specialists into a single answer. ``` **3. Attach specialists** in the coordinator's General tab. Scroll to **Multi-Agent**, click **Attach agents**, and select the specialist agents from the panel. Attach agents panel **4. Deploy the coordinator** through any channel. The Channels tab shows all available deployment options: API, SDK, Chat, Slack, Webhook, Task, MCP, and A2A. Agent Channels tab ## A2A protocol for cross-platform delegation For agents that need to communicate across organizations, Xpander supports Google's Agent2Agent (A2A) protocol. Enable it in the **Channels** tab to get an A2A URL and agent card. A2A agent card External A2A-compatible agents can invoke your agent at that URL, and your agent can invoke theirs. **A2A vs. attached agents:** Attached agents coordinate within your Xpander workspace. A2A is for cross-platform communication between agents on different systems. ## When to use multi-agent Use it when: * The coordinator's system prompt is getting too long because it handles too many domains * Different domains need different tool sets, and combining them confuses the model * You want reusable specialists (one Salesforce agent attached to multiple coordinators) A single agent is fine when the task stays within one domain. Don't add multi-agent complexity unless the single-agent approach is struggling. ## What's next Select the right model for each agent and task type. Backend automation on the visual canvas. # Multi-Model Reasoning Source: https://docs.xpander.ai/guides/agentic-automation/multi-model-reasoning Select different AI models for different agents and workflow steps based on what each task requires. Xpander connects to multiple LLM providers through a single interface. You can assign different models to different parts of your system so a ticket classifier runs on a fast, cheap model while a customer response agent uses a frontier model. ## Supported providers | Provider | Example models | | -------------------- | ------------------------------------------------------ | | **Anthropic** | Claude Opus 4.6 (T1), Sonnet 4.6 (T2), Sonnet 4.5 (T2) | | **OpenAI** | GPT-5.4 (T1), GPT-5 (T2), GPT-5 Mini (T3), GPT-4o (T2) | | **Google AI Studio** | Gemini models | | **Amazon Bedrock** | Claude and Titan via AWS | | **Azure AI Foundry** | Azure-hosted models | | **Nvidia** | NIM-hosted models | | **Fireworks** | Fast inference models | | **OpenRouter** | Multi-provider routing | The table above shows common examples. The full list varies by plan. Also available: Nebius Token Factory, Cloudflare AI Gateway, Tzafon LightCone, ByteDance ModelArk. Provider dropdown expanded Each provider shows a **Featured** tab (curated models) and a **Custom** tab (enter any model ID). Models are labeled by tier: T1 (most capable), T2 (balanced), T3 (fast/cheap). Use Xpander's built-in API access (no keys needed) or [bring your own credentials](/guides/agents/ai-models-intelligence#bring-your-own-keys) through Admin Settings (enterprise plans). ## Model selection hierarchy More specific settings override broader ones: ```text theme={"dark"} Org default (Admin Settings) └── Per-agent (Agent > General > LLM Settings) └── Per-workflow (Workflow > Settings > LLM Settings) └── Per-node (Classifier / Summarizer / Guardrail) ``` Agent LLM advanced config **Org default:** New agents and workflows inherit this unless overridden. Configure in Admin Settings, LLM Settings tab. Admin LLM settings **Per-agent:** Each agent picks its own provider and model in the General tab. This is where most model decisions happen. Agent LLM settings **Per-workflow:** Applies to all AI nodes in a workflow unless a specific node overrides it. **Per-node:** Classifier, Summarizer, and Guardrail nodes each have independent LLM settings in Advanced Configuration. **Agent nodes don't have LLM settings.** They inherit the model from the agent you selected. Only Classifier, Summarizer, and Guardrail have per-node model selection. ## Pick the right tier for the task | Tier | Cost | Speed | Use when | | ------------------- | -------- | -------- | ------------------------------------------------------------------- | | **T1** (frontier) | Highest | Slowest | Complex reasoning, customer-facing responses, compliance evaluation | | **T2** (balanced) | Moderate | Moderate | Classification, summarization, data extraction. Best default. | | **T3** (fast/cheap) | Lowest | Fastest | High-volume routing, sentiment detection, simple categorization | ### Example: mixed models in one workflow ```text theme={"dark"} [Webhook trigger] │ ▼ [Classifier] ← T3 (GPT-5 Mini): route tickets by category │ ├── Billing ──► [Agent] ← T1 (Claude Opus): draft accurate refund response │ │ │ ▼ │ [Guardrail] ← T2 (Claude Sonnet): check policy compliance │ └── Technical ──► [Agent] ← T2 (Claude Sonnet): look up docs + draft fix │ ▼ [Summarizer] ← T3 (GPT-5 Mini): compress for internal log ``` The classifier runs on T3 because routing is straightforward. The billing agent uses T1 because refund responses need precision. The guardrail uses T2 for balanced quality and speed. The summarizer uses T3 because internal logs don't need frontier quality. ## Output formats Each agent supports four output formats in the General tab: **Default** (text), **Markdown**, **Structured output** (JSON to a schema), and **Voice** (audio). Structured output is particularly useful in multi-agent setups. A specialist returning JSON is more reliable for the coordinator to parse than free text. ## What's next Coordinate specialized agents on shared tasks. Backend automation on the visual canvas. # Agent Configuration Source: https://docs.xpander.ai/guides/agents/agent-configuration Create an agent, pick where it runs, and configure every control in the Agent Studio This page is being phased out. For the current way to configure an agent, see [Apps and Agents](/guides/omni/manage-agents/agent-configuration) and [Build an Agentic App](/guides/omni/agentic-applications/build-your-first-agentic-application) in the User Guide. Personal Agents are great for day-to-day assistance, but you can create **Specialized Custom Agents** for dedicated tasks like customer support, weekly reporting, and bug hunting. Custom Agents run on the [**Agno** framework](https://docs.agno.com/introduction) and give you full control over the model, memory, instructions, tools, and channels. Need to run on a framework other than Agno (e.g., OpenAI Agents SDK, LangChain, Google ADK, AWS Strands)? Framework choice is available on the **Enterprise** plan. [Contact sales](https://cal.com/team/xpander-ai/activate) to enable it for your workspace. ## Create Your Agent Go to [chat.xpander.ai](https://chat.xpander.ai) and sign in or sign up. New users get a 14-day free trial. Click + New Agent in the top right of the Agents page. xpander Agents page with the + New Agent button in the top right Environment will already be set to `xpander-cloud`, which is the default hosting setup, fully-managed by Xpander. Create New Agent dialog with Agent name field and Environment dropdown showing xpander cloud On the **Self-hosted Enterprise plan**, you can spin up Xpander's AI Agents on your own compute environments. [Contact sales](https://cal.com/team/xpander-ai/activate) to learn more. Xpander sets up your agent's container and wires up memory, built-in tools, and networking. This one-time setup takes a minute or two. Agent setup modal showing container spinning up You're ready to try out your newly created agent. Click the **gear** icon in the top left to open the configuration panel. Agent Studio showing Builder view with chat interface and gear icon When you're ready, click Publish in the top right. You need to publish every time you change configuration before it takes effect. ## Tour the Agent Studio The Agent Studio has two views: * **Builder**: Configure your agent and chat with it directly * **Monitor**: View conversation logs, performance metrics, and task history Agent Studio header showing Builder and Monitor tabs ## Configuration Quick Reference Xpander's Custom Agents expose full Agno configuration options. Click the **gear** icon in the Builder view to open the configuration panel. Agent Studio configuration panel with General, Instructions, Tools, Channels, and Memory tabs | Tab | What you configure | | ---------------- | -------------------------------------------------------- | | **General** | Model, access, output format, guardrails, notifications. | | **Instructions** | System prompt - role, goals, rules, expected output. | | **Tools** | Built-in tools, connectors, thinking controls. | | **Channels** | API, SDK, Chat, Slack, Webhook, Task, MCP, A2A. | | **Memory** | Session history, user and agent memories, compression. | ### General High-level agent properties and model selection. | Setting | What it does | | ------------------- | ------------------------------------------------------------------------------------------------------------------------------------------ | | **Name** | Your agent's display name. | | **LLM settings** | Pick a provider and model. See [AI Models & Intelligence](/guides/agents/ai-models-intelligence). | | **Access** | Private to you, or shared with your organization. | | **Output format** | Free-form text, Markdown, Structured output, or Voice. | | **Learning** | Capture user profiles and knowledge over time. See [Memory & State](/guides/agents/memory-state). | | **LLM Guardrails** | PII detection, prompt injection blocks, and OpenAI moderation. See [LLM Guardrails](/guides/agents/ai-models-intelligence#llm-guardrails). | | **Multi-Agent** | Attach other agents for orchestration. | | **Knowledge bases** | Attach knowledge bases for retrieval. See [Knowledge Bases](/guides/agents/knowledge-bases). | | **Templates** | Save the current configuration as a reusable template. | | **Notifications** | Success and error alerts via Email, Webhook, or Slack. | | **Danger zone** | Disable or delete the agent. | ### Instructions The agent's system prompt. Instructions tab showing agent role, goals, instructions, and expected output fields | Field | What it does | | ------------------- | ------------------------------------------ | | **Agent role** | The agent's role or personality. | | **Goals** | What the agent should accomplish. | | **Instructions** | Rules and behavior constraints. | | **Expected output** | How the agent should format its responses. | Click Write instructions with AI to prompt an LLM to fill these fields for you. ### Tools Built-in tools, connectors, and thinking controls. See [Tools & Connectors](/guides/agents/tools-connectors). Tools tab showing built-in tools, connector tools, thinking & planning, and advanced configuration | Section | What it does | | ----------------------------- | --------------------------------------------------------------------------------------------------------------------------------------- | | **Built-in tools** | Toggle xpander's built-in tools (Send Email, OCR, etc.). | | **Tools** | Connect external apps via MCP or API. See [Tools & Connectors](/guides/agents/tools-connectors). | | **Agent Thinking & Planning** | Checklist Toolkit, Checklist Enforcement, and Reasoning Toolkit. See [AI Models & Intelligence](/guides/agents/ai-models-intelligence). | | **Advanced Configuration** | Max tool calls per run. | ### Channels How users and systems reach your agent - API, SDK, Chat, Slack, Webhook, Task, MCP, and A2A. See [Deploy an Agent](/guides/agents/deploy-agent) for setup on each channel. Channels tab showing API, SDK, Chat, Slack, Webhook, Task, MCP, and A2A options ### Memory What the agent remembers across conversations. See [Memory & State](/guides/agents/memory-state). Memory tab showing session storage, memories, compression, and optimization settings | Setting | What it does | | -------------------------------- | --------------------------------------------- | | **Session storage** | Persist chat history across sessions. | | **User Memories** | Store per-user memories. | | **Agent Memories** | Store agent-wide memories across all users. | | **Max tool calls from history** | Cap tool calls included in context. | | **Session summaries** | Summarize long conversations automatically. | | **Tool calls compression** | Shrink verbose tool outputs in context. | | **Memory optimization strategy** | Optimize the context window during execution. | ## Common Use Cases | I want my agent to... | What to configure | | ---------------------------------------------- | ------------------------------------------------------------------------------------------------------- | | Answer questions about my company's docs | Attach a [Knowledge Base](/guides/agents/knowledge-bases) with your documents | | Send emails and search the web | Enable [built-in tools](/guides/agents/tools-connectors) (Send Email, Web Search) | | Integrate with Slack, Jira, GitHub, etc. | Install [connector tools](/guides/agents/tools-connectors) from the catalog | | Remember user preferences across conversations | Enable [User Memories](/guides/agents/memory-state) in the Memory tab | | Learn and improve over time | Enable [Agent Memories](/guides/agents/memory-state) with agentic management | | Handle complex multi-step tasks | Enable [Checklist Toolkit or Planning Mode](/guides/agents/ai-models-intelligence) | | Give deeper, more thorough answers | Enable [Reasoning Toolkit](/guides/agents/ai-models-intelligence) or increase reasoning effort | | Respond in structured JSON | Set **Output format** to Structured output in General tab | | Run on a framework other than Agno | [Contact sales](https://cal.com/team/xpander-ai/activate) to enable framework choice on Enterprise | | Run agents in your own infrastructure | [Contact sales](https://cal.com/team/xpander-ai/activate) to enable self-hosted locations on Enterprise | ## Next Steps Browse 100+ connectors and configure tool behavior Providers, planning mode, and reasoning mode Session storage, user memories, and agent memories Publish and connect to Slack, API, SDK, and more # AI Models & Intelligence Source: https://docs.xpander.ai/guides/agents/ai-models-intelligence Choose your LLM provider, configure intelligence features, and define your agent personality This page is being phased out. For the current approach to choosing a model, see [Models and Memory](/guides/omni/manage-agents/models) in the User Guide. Every Xpander agent is powered by a large language model. The model determines how your agent thinks, how it writes, how much it costs, and how fast it responds. This page covers: * [Models](#models): choose a provider, bring your own keys, configure extra headers * [Model Settings](#model-settings): temperature and reasoning effort * [Planning Mode](#planning-mode): structured task decomposition and progress tracking * [Reasoning Mode](#reasoning-mode): extended thinking for complex problems * [Multi-Agent Orchestration](#multi-agent-orchestration): delegate tasks to specialized agents ## Models To change what model your agent uses: In the Agent Studio, click the **gear** icon and go to **General** → **LLM Settings**. Select your provider from the dropdown. If using built-in keys, you're done. Xpander handles billing. If using your own keys, enter them in the API key field. Pick from the **Featured** models list, or toggle to **Custom** and enter any model ID your provider supports. Custom mode is useful for fine-tuned models, newly released models, or provider-specific variants. Click **Publish** to apply the new model. Your agent will use it for all subsequent conversations. ### Supported Providers **Built-in access (pay-as-you-go) or BYOK** * GPT-5.4, GPT-5.3 Chat, GPT-5.2, GPT-5.1, GPT-5 Nano, GPT-5, GPT-5 Mini * GPT-4.1, GPT-4.1-mini * GPT-4o, GPT-4o Mini, GPT-4 Turbo * GPT-3.5 Turbo **Built-in access (pay-as-you-go) or BYOK** * Claude Sonnet 4.6, Claude Opus 4.6 * Claude Sonnet 4.5, Claude Opus 4.5 * Claude Opus 4, Claude Sonnet 4 * Claude Sonnet 3.7, Claude Sonnet 3.5 **BYOK: requires AWS credentials with Bedrock access** * Claude Sonnet 4.6, Claude Opus 4.6 * Claude Sonnet 4.5, Claude Opus 4 * Claude Sonnet 4, Claude Sonnet 3.7, Claude Sonnet 3.5 * Claude Haiku 3.5 * Amazon Titan Text Express **BYOK: requires Azure AI Foundry credentials** Azure AI Foundry provides access to OpenAI models through Azure's infrastructure. * GPT-5.2, GPT-5.1, GPT-5 Nano, GPT-5, GPT-5 Mini * GPT-4.1, GPT-4.1-mini * GPT-4o, GPT-4o Mini * GPT-4 Turbo, GPT-3.5 Turbo Set the API Base URL to include your deployment name without the completions path: `https://your-resource.openai.azure.com/openai/deployments/gpt-4o` Do NOT include `/completions?api-version=...` at the end. **BYOK: requires ByteDance ModelArk API key** No featured models. Custom model identifier only. Access ByteDance's model inference platform by entering your model ID in Custom mode. **BYOK: requires Fireworks AI API key** * GLM-4.6 * Kimi K2 Instruct 0905 * DeepSeek V3.1 * OpenAI gpt-oss-120b, OpenAI gpt-oss-20b * Qwen3 235B A22B Thinking 2507, Qwen3 235B A22B Instruct 2507 **BYOK: requires Google AI Studio API key** * Gemini 2.0 Flash, Gemini 2.0 Flash Lite * Gemini 2.5 Pro, Gemini 3 Pro **BYOK: requires NVIDIA API key** **Meta Llama Models:** * Llama 3.1 8B Instruct, Llama 3.1 70B Instruct, Llama 3.1 405B Instruct * Llama 3.2 1B Instruct, Llama 3.2 3B Instruct * Llama 3.3 70B Instruct * Llama 4 Scout 17B, Llama 4 Maverick 17B **Mistral Models:** * Mistral 7B Instruct v0.3, Mistral Small 3.2 24B Instruct **NVIDIA Nemotron:** * Nemotron Nano 4B v1.1, Nemotron Nano 8B v1, Nemotron Ultra 253B v1 ### Supported Gateways **BYOK: requires Cloudflare API key + base URL** No featured models. Requires a custom model identifier, API key, and base URL. Cloudflare AI Gateway provides caching, rate limiting, and observability for LLM requests. **BYOK: requires Nebius API key** Nebius provides inference for open-source models. **Meta Llama:** * Meta-Llama-3.1-8B-Instruct-fast, Meta-Llama-3.1-8B-Instruct, Llama-Guard-3-8B **NVIDIA:** * Llama-3.1-Nemotron-Ultra-253B-v1, Nemotron-Nano-V2-12b **Google Gemma:** * gemma-2-2b-it, gemma-2-9b-it-fast, gemma-3-27b-it, gemma-3-27b-it-fast **Qwen:** * Qwen2.5-Coder-7B-fast, Qwen3-235B-A22B-Instruct-2507, Qwen3-235B-A22B-Thinking-2507 * Qwen3-32B, Qwen3-32B-fast, Qwen2.5-VL-72B-Instruct * Qwen3-Coder-30B-A3B-Instruct, Qwen3-Coder-480B-A35B-Instruct **DeepSeek:** * DeepSeek-R1-0528 **Nous:** * Hermes-4-70B, Hermes-4-405B **Others:** * INTELLECT-3, Kimi-K2-Thinking **Image Generation:** * flux-dev, flux-schnell **BYOK: requires OpenRouter API key** OpenRouter provides unified access to 200+ models with automatic fallback, load balancing, and unified pricing. **Featured:** * Prime Intellect: INTELLECT-3 * TNG: R1T Chimera (free), TNG: R1T Chimera **Anthropic:** * Claude Opus 4.5, Claude Sonnet 4.5, Claude Haiku 4.5, Claude Opus 4.1 **AllenAI:** * OLMo 3 32B Think, OLMo 3 7B Instruct, OLMo 3 7B Think **LiquidAI:** * LFM2-8B-A1B, LFM2-2.6B **IBM:** * Granite 4.0 Micro **Deep Cogito:** * Cogito V2 Preview Llama 405B **OpenAI:** * GPT-5 Image Mini, GPT-5 Pro, GPT-4o Audio, gpt-oss-120b, gpt-oss-20b (free), gpt-oss-20b **Google:** * Gemini 2.5 Flash Image (Nano Banana), Gemini 2.5 Flash Image Preview (Nano Banana) **Qwen:** * Qwen3 VL 8B Thinking, Qwen3 VL 8B Instruct, Qwen3 VL 30B A3B Thinking, Qwen3 VL 30B A3B Instruct * Qwen3 Coder 30B A3B Instruct, Qwen3 30B A3B Instruct 2507 **Z.AI:** * GLM 4.6, GLM 4.6 (exacto) **DeepSeek:** * DeepSeek V3.2 Exp, DeepSeek V3.1 **Nous:** * Hermes 4 70B, Hermes 4 405B **Mistral:** * Mistral Medium 3.1, Codestral 2508 **Baidu:** * ERNIE 4.5 21B A3B, ERNIE 4.5 VL 28B A3B **Bert:** * Nebulon Alpha **BYOK: requires Tzafon LightCone API key** No featured models. Custom model identifier only. Access models through Tzafon's LightCone inference platform by entering your model ID in Custom mode. ### Bring Your Own Keys Contact Sales to enable Bring your Own LLM Keys for your organization. When you bring your own keys, you get full control over billing and model access. Enter your provider's API key in the LLM Settings panel. For providers like Azure or AWS Bedrock that need additional configuration (deployment IDs, regions), fill in the extra fields that appear. You can also set a custom **API Base URL** to route requests through your own AI gateway or proxy. If your AI Gateway is behind a private subnet or firewall, make sure to run Xpander in the same network with access to those models. ### Use Custom Models The models listed above are featured models that have been tested with Xpander. To use a different model from your provider, select **"Custom"** in the model dropdown and enter the model name exactly as specified by your provider (e.g., `custom-model-id`). This is particularly useful for: * Private or fine-tuned models only you have access to * Newly released models not yet in the dropdown * Provider-specific model variants with custom endpoints ### Model Settings Two settings fine-tune how the model generates responses. Configure these in the **General** tab → **LLM Settings** panel. | Setting | What it does | Range | | -------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ------------------- | | **Temperature** | Controls randomness. Lower values (0.0–0.3) give more focused, deterministic responses. Higher values (0.7–1.0) give more creative, varied responses. | 0.0–1.0 | | **Reasoning Effort** | Controls how much effort the model puts into reasoning before responding. Higher effort means slower but more thorough answers. Currently only visible when using **OpenAI** models. | Low / Medium / High | ### LLM Extra Headers You can configure custom HTTP headers to be sent with every LLM request. This is useful for: * Sending custom authentication tokens to AI Gateways * Adding tracking or metadata headers (e.g., `X-Request-ID`, `X-Organization-ID`) * Passing compliance or security headers required by your infrastructure * Integration with observability platforms like Helicone, LangSmith, or custom proxies **Configuration levels:** 1. **Organization Default Headers**: Set default headers at the organization level in [**Admin Settings → LLM Settings**](https://platform.xpander.ai/admin_settings#llm_settings) that apply to all agents 2. **Agent-Specific Override**: Override organization defaults with agent-specific headers in the Agent Studio **General** → **LLM Settings** panel Agent-level headers take precedence and merge with organization defaults (agent headers override matching keys). **Supported Providers:** Extra headers are currently supported for OpenAI, Helicone, Nebius, OpenRouter, Fireworks, and NVIDIA NIM providers. For Anthropic, headers are sent as `default_headers`. Google AI Studio and Amazon Bedrock don't support custom headers. Track and monitor all LLM requests through Helicone: ```json Organization Headers (Admin Settings) theme={"dark"} { "Helicone-Auth": "Bearer sk-helicone-xxx", "Helicone-Property-Environment": "production" } ``` ```json Agent Headers (Agent Studio) theme={"dark"} { "Helicone-Property-Agent": "support-agent", "Helicone-User-Id": "team-support" } ``` Route requests through your internal AI Gateway with authentication: ```json Organization Headers theme={"dark"} { "X-Gateway-Token": "your-gateway-token", "X-Tenant-ID": "company-prod" } ``` Add tracking and compliance headers for audit logs: ```json Organization Headers theme={"dark"} { "X-Request-Source": "xpander-platform", "X-Compliance-Level": "gdpr-compliant", "X-Data-Region": "eu-west-1" } ``` Differentiate between development and production environments: **Production Org Headers:** ```json theme={"dark"} { "X-Environment": "production", "X-Rate-Limit-Tier": "premium" } ``` **Dev Agent Override:** ```json theme={"dark"} { "X-Environment": "development", "X-Debug-Mode": "enabled" } ``` ## Planning Mode Planning Mode gives your agent the ability to break complex tasks into structured, trackable steps. When enabled, the agent receives a set of to-do list tools and is nudged to create a checklist before starting work. It then works through the items one by one, marking each complete and reporting progress along the way. ### How to Enable In the Agent Studio, go to the **Tools** tab → **Agent Thinking & Planning** section: * **Checklist Toolkit**: Toggle this on to give the agent planning tools. The agent will be nudged to create a plan and work through it. * **Agent Checklist Enforcement** (Beta): When enabled, execution blocks entirely until the agent creates a plan. Without this, the agent is encouraged to plan but not forced to. Agent Thinking & Planning section showing Checklist Toolkit and Reasoning Toolkit toggles ### How It Works Planning Mode gives the agent tools to create, update, and manage a to-do list. The typical flow looks like this: 1. The agent receives a prompt and creates a checklist of steps it needs to complete 2. It works through each item, using its tools and marking tasks done as it goes 3. If it discovers new work along the way, it adds items to the list dynamically 4. The checklist updates in real-time in both the chat interface and the Monitor tab 5. If tasks remain incomplete after a run, the system retries automatically based on the configured retry strategy The agent can also remove tasks that turn out to be unnecessary, or update task descriptions as requirements become clearer during execution. ### Retry Strategies Planning Mode also nudges the Agent to complete its checklist before finishing its response. If some tasks remain incomplete, it prompts the agent to retry. | Strategy | Behavior | | -------------- | ----------------------------------------------------------------------------------------------------- | | **Tiered** | Lightweight nudge first (retries 1–3), then full context compaction on retry 4+. This is the default. | | **Aggressive** | Always compacts context on every retry. Use when the agent consistently fails due to long context. | | **Disabled** | No automatic retries. The execution ends after the first attempt, even if tasks are incomplete. | **Tiered** is the best default for most agents. It gives the agent a chance to finish naturally before resorting to context compaction, which can lose some detail from earlier in the conversation. ### When to Use Planning Mode | Good fit | Not a good fit | | ------------------------------------------------------------- | ---------------------------------- | | Multi-step workflows (research → draft → review) | Simple Q\&A | | Tasks requiring coordinated actions across tools | Single tool calls | | Audit trails where you need to see exactly what the agent did | Real-time chat where speed matters | | Complex implementations or migrations | Quick lookups | ## Reasoning Mode Reasoning Mode exposes a `think` tool that gives the agent a private scratchpad for extended thinking. Instead of responding immediately, the agent can reason through the problem step-by-step, considering multiple approaches, evaluating tradeoffs, and self-correcting before delivering a final answer. Reasoning steps are visible in the activity log and the chat interface, and are delivered in real-time as `think` events when streaming. To enable it, go to the **Tools** tab → **Agent Thinking & Planning** section and toggle on **Reasoning Toolkit**. No additional configuration is needed. Reasoning Toolkit toggle in the Agent Thinking & Planning section Reasoning Mode produces higher-quality answers at the cost of speed and tokens. Use it selectively for tasks where accuracy matters more than speed. ## Multi-Agent Orchestration Your agent can call other agents in your workspace to handle specialized tasks. Instead of building one agent that does everything, you can create focused agents and connect them together. For example: create 3 specialized agents: a research agent, a writing agent, a data analysis agent. Each has its own knowledge bases, tool connections, and system prompts. Then create a primary agent that delegates work to whichever specialist is best suited. In the Agent Studio, scroll down to the **Multi-Agent** section and expand it. Click **+ Attach agents**. A panel opens showing all agents in your workspace. Select the agents you want this agent to be able to call. Click **+ Add to agent** to confirm. The attached agents now appear as available tools the primary agent can invoke during execution. Multi-Agent section showing attached agents panel Once attached, the primary agent can decide when to delegate a task to another agent based on its instructions and the nature of the request. Each sub-agent runs independently with its own tools, memory, and configuration, and can even have its own planning checklist if Planning Mode is enabled. Sub-agent executions are tracked separately in the Monitor tab, so you can drill into any agent's run to see exactly what it did. ## LLM Guardrails Safety checks applied to user input and model output before and during each run. Configure them under the **LLM Guardrails** section in the Agent Studio **General** tab. LLM Guardrails section with PII Detection, prompt injection detection, and OpenAI moderation toggles | Guardrail | What it does | | ------------------------------ | ------------------------------------------------------------------------------------------------- | | **PII Detection** | Block runs when user input contains credit cards, emails, SSNs, or phone numbers. | | **Mask detected PII** | Replace PII with `****` instead of blocking. | | **Prompt injection detection** | Block attempts to manipulate the agent's behavior through malicious or unauthorized instructions. | | **OpenAI moderation** | Block content that violates OpenAI's content policy. | Turn on **Prompt injection detection** for any agent exposed to public or untrusted users. Use **Mask detected PII** instead of blocking when you want the agent to keep working without ever seeing the raw sensitive data. ## Next Steps Test model behavior and intelligence features Give your agent actions to take Configure what your agent remembers Publish and connect to channels # Deploy an Agent Source: https://docs.xpander.ai/guides/agents/deploy-agent Deploy your agent to channels, and share templates with team Once your agent is published, you can connect it to channels so users can reach it outside the Agent Studio. This page covers setup for each channel: Chat, Slack, scheduled tasks, MCP, A2A, REST API, SDK, and webhooks. ## Deploy on Channels In the Agent Studio, click the gear icon and go to the **Channels** tab to see all available channels. Channels tab showing all available deployment channels | Channel | Best for | How users interact | | ------------------- | --------------------------------------------- | --------------------------------------------------------- | | **Chat Widget** | Internal teams, customer portals | Hosted URL or embedded iframe with threaded conversations | | **Slack** | Teams already in Slack | DM or @mention the bot, auto-engage on topics | | **Webhooks** | Automation platforms, CI/CD, custom apps | HTTP POST, sync or async response | | **MCP** | Developers in Claude Desktop, Cursor, VS Code | Agent appears as a native MCP tool | | **Scheduled Tasks** | Recurring reports, monitoring, data syncs | No user trigger, runs on a cron schedule | ### Chat The hosted Chat channel is being phased out. For the current chat experience, see [Channels](/guides/omni/manage-agents/channels) in the User Guide. A hosted Chat UI with a unique, shareable URL. No embedding or code required. See [Chat Widget](/guides/deploy/chat-widget) for full setup, embedding, conversation starters, and access control. Your Chat UI URL is displayed (e.g., `https://peach-centipede.agents.xpander.ai`). Share this link directly with users who have access. Chat UI with Xpander branding, message input, and conversation starters Click Conversation starters to add prompt suggestions that appear when a user opens the chat for the first time. Add, edit, or remove starters, then click Save. Chat conversation starters editor with example prompts Only users set in the **Access** setting (in the **General** tab) can access this link. Set it to **Only me** for private use or **All users in my account** to share with your team. Supports platform authentication (Xpander built-in) or SSO (SAML, OAuth 2.0 with Okta, Auth0, Azure AD). Access setting dropdown with Only me and All users in my account options ### Slack Slack setup here is being phased out. For the current way to connect Slack, see [Channels](/guides/omni/manage-agents/channels) in the User Guide. Connect your agent as a Slack bot that users can DM or @mention in channels. See [Slack](/guides/deploy/slack) for the full setup flow, file processing capabilities, auto-engage rules, and conversation starters. In the Channels tab, click Connect to Slack agent. A dialog opens letting you create a new Slack agent or link to an existing one. Click Create new Slack agent. Connect to Slack agent dialog with options to create new or view existing You'll need: * A name for your Slack bot * Access tokens and Refresh tokens (See next step) New Slack agent setup page with empty name and token fields Go to [api.slack.com/apps](https://api.slack.com/apps). Under **Your App Configuration Tokens**, click Generate Token. Slack API Your Apps page with Generate Token button In the dialog, select the Slack workspace you want your agent to work in from the dropdown and click Generate. Each Slack workspace needs its own Xpander Slack agent, but you can connect a single Xpander agent to multiple Slack agents across workspaces. Generate Your App Configuration Token dialog with workspace selection Once generated, you'll see your **Access Token** and **Refresh Token** with Copy buttons. Copy both. Slack API tokens page showing Access Token and Refresh Token with Copy buttons Back on the Xpander setup page, enter a **Slack agent name**, paste the **Access Token** and **Refresh Token**, then click Connect to Slack. Slack will prompt you to review permissions for the Xpander app. Click Allow. Slack OAuth permissions page. Allow Xpander to access Slack Once connected, you'll see "Xpander created successfully". Add the Slack channels the bot should be active in and click Add to channels. Then in the **Connect agent** section below, select the Xpander agent (or workflow) to connect and click Connect agent. Slack agent page with successful connection, channel selection, and Connect agent button Back in the Agent Studio, click Publish to make the agent live in Slack. To manage, customize, or delete Slack agents after setup, go to the [Slack Agents page](https://chat.xpander.ai/slack_agents/). From there you can change the connected Xpander agent, configure capabilities (OCR, audio transcription), set auto-engage rules, or delete the Slack agent entirely to revoke access. ### Task (Scheduled) Run your agent on a recurring schedule. Use this for daily reports, periodic data syncs, monitoring checks, or other automated work. See [Scheduled Tasks](/guides/deploy/scheduled-tasks) for cron expressions, custom schedules, run-as-user context, and monitoring scheduled runs. Open the **Task** section in the Channels tab and click Add Task. Task channel card showing Add Task button and existing tasks Fill in the task configuration: * **Instructions**: Describe what the agent should do on each scheduled run * **Schedule**: Choose a **Quick Preset** (e.g., every 5 minutes) or set a **Custom Schedule** with interval, specific time, and active days * **User context** (under Advanced Settings): Provide an email, user ID, and name so the agent runs with a specific user identity. Without it, the agent runs as an anonymous user with no memory context. Task configuration with instructions, schedule presets, interval settings, and user details ### MCP (Model Context Protocol) Expose your agent as an MCP server so any MCP client can invoke it. See [MCP Protocol](/guides/deploy/mcp) for client-specific configurations (Claude Desktop, Cursor, VS Code, ChatGPT), available MCP tools, and OAuth flow. Toggle MCP on in the Channels tab, then click Details. The modal shows your **MCP server URL**, **API key**, and **transport** options (HTTP or SSE). The modal provides ready-to-paste configuration for **Cursor**, **Claude**, **Windsurf**, or **Raw JSON**. Copy and paste it into your MCP client's config file. MCP details showing server URL, API key, transport selection, and easy setup configs for Cursor, Claude, Windsurf ### A2A (Agent-to-Agent) A2A channel card with Enabled toggle, Agent card and Manage API keys buttons Let other agents (inside or outside your organization) discover and invoke this agent via Google's Agent2Agent protocol. Open the **A2A** section in the Channels tab and enable it. Click Agent card to see your agent's A2A identity, including the Agent A2A URL, name and version. A2A agent card showing URL, name, version, and list of exposed skills with descriptions Click Manage API keys to open the A2A key manager. Click Assign API Keys to generate credentials that external agents use to authenticate. A2A API key manager with Assign API Keys dropdown showing generated keys ### API Call your agent programmatically via the REST API. Click Test to open the Agent API Tester. Agent API Tester with payload URL, API key, cURL command, and invoke mode selection The tester shows your **Payload URL** and **API Key** at the top. Copy these for your integration. It also generates a ready-to-use **cURL command**. Choose an invocation mode: | Method | Endpoint | When to use | | ------------ | ------------------------------------------ | ----------------------------------------------------- | | Synchronous | `POST /v1/agents/{agent_id}/invoke` | Simple integrations. Blocks until the agent finishes. | | Asynchronous | `POST /v1/agents/{agent_id}/invoke/async` | Background jobs. Returns a task ID immediately. | | Streaming | `POST /v1/agents/{agent_id}/invoke/stream` | Chat UIs. Delivers SSE events in real-time. | All three support multimodal input (text, files, and images in the same request). Set a JSON payload in the **Request Examples** section and click Test API. The response appears in the **Response History** panel. ### SDK SDK channel card showing Agent ID and Manage API keys button Integrate your agent into custom applications using the Xpander SDK. Open the **SDK** section in the Channels tab. Your Agent ID is displayed there. Click Manage API keys to open the SDK modal. Click Assign API Keys to generate or select a key for your application. SDK modal showing Agent ID and Assign API Keys dropdown Expand the Assign API Keys dropdown to reveal your key. Copy it for use in your application. SDK modal with API key expanded and visible Follow the [SDK documentation](/api-reference/backend) to integrate the agent into your app. ### Webhook Trigger your agent from Zapier, Make, n8n, etc. See [Webhooks](/guides/deploy/webhooks) for sync vs async modes, file uploads, response field extraction, dynamic parameter mapping, and MCP OAuth pass-through. Open the **Webhook** section in the Channels tab and toggle it on. Then click Configure and test to open the Agent Webhook Tester. The tester shows your **Payload URL** (with agent ID and API key embedded) and a ready-to-use **cURL command**. Copy these for your integration. Key parameters you can set in the payload: * **message**: the prompt to send to the agent * **asynchronous**: set to `true` for async mode (returns task ID immediately) * **task\_id**: optionally continue an existing conversation thread * **getter**: extract a specific field from the agent's response (e.g., `result`) Choose an input format: **JSON**, **Form Data**, or **Multipart**. Set your payload fields. Click Test Webhook to send a test request. The response appears in the **Response History** panel. Agent Webhook Tester with payload URL, API key, cURL command, JSON payload fields, and Test Webhook button ## Share Agent Template You can share your agent's configuration with your team as a reusable template. Use this to: * Create similar agents quickly * Share proven configurations with your team * Backup a known-good configuration before making major changes In the Agent Studio **General** tab, expand the **Templates** section. Templates section in the General tab showing saved templates with Use template buttons Click Save as template. This captures your agent's complete configuration (instructions, tools, memory settings, model, and channels) as a named template with a timestamp. Saved templates appear in the list with a Use template button. Click it to create a new agent pre-configured with that template's settings. ## Next Steps Adjust settings and re-publish Debug issues found in production Add more capabilities to your deployed agent Tune memory for production workloads # Knowledge Bases Source: https://docs.xpander.ai/guides/agents/knowledge-bases Upload documents and give your agent searchable, citable knowledge Without a Knowledge Base, your agent only knows what the LLM was trained on. With a Knowledge Base, it can search your actual documents (company policies, product docs, FAQs, spreadsheets) and ground its answers in real information. This is **Retrieval-Augmented Generation (RAG)**. When a user asks a question, Xpander searches your uploaded documents for relevant chunks and injects them into the agent's context before it responds. The result: fewer hallucinations, more accurate answers, and the ability to cite sources. Knowledge Bases page showing list of knowledge bases This page covers: * [Create a Knowledge Base](#create-a-knowledge-base): upload and index your documents * [Attach to your agent](#attach-to-your-agent): connect a Knowledge Base to an agent * [Tuning relevance](#tuning-relevance): control search quality with Top K and similarity threshold * [Best practices](#best-practices): structure documents for better retrieval ## Create a Knowledge Base Go to [Knowledge Bases](https://chat.xpander.ai/knowledge-bases) from the left sidebar. You'll see all Knowledge Bases in your organization. Click + Create New in the top right. Create Knowledge Base dialog with name and description fields Enter a **name** and optional **description**. Use a name that describes the content (e.g., "Product Documentation," "HR Policies," "Sales Playbook"). Already have a vector database? You can bring a compatible one and expose it to your agent as a tool. [Contact Xpander](https://cal.com/team/xpander-ai/activate) to set this up. Inside your new Knowledge Base, click Upload File. Drag and drop files or use the upload dialog. Maximum file size is 50 MB. Upload dialog with drag and drop area Xpander accepts a wide range of file types: | Category | Formats | | ----------------- | ----------------------- | | **Documents** | PDF, DOCX, TXT, MD, RTF | | **Spreadsheets** | XLSX, CSV | | **Presentations** | PPTX | | **Web & Data** | HTML, JSON, YAML, XML | Xpander processes each document through a pipeline: extract text, chunk into segments, generate vector embeddings, and index in the vector database. This typically takes 10–60 seconds per document. Knowledge Base detail page showing uploaded documents Once processing completes, your documents are searchable. You can also click + Add external on the Knowledge Bases page to connect an external vector database instead of using Xpander's built-in one. ## Attach to Your Agent Creating a Knowledge Base doesn't automatically make it available to an agent. You need to attach it. In the Agent Studio, click the **gear** icon and go to the **General** tab. Scroll down to the **Knowledge Bases** section. Choose the **Knowledge bases toolkit**. This determines the vector database used for search. The default is **Xpander built-in vector database**. Under **Add knowledge base**, select your Knowledge Base from the dropdown and click Add. Agent General tab showing Knowledge Bases section with toolkit selection and attached Knowledge Base Click Publish to push the changes live. Your agent now automatically searches this Knowledge Base when answering questions. You can attach multiple Knowledge Bases to the same agent. The agent searches across all of them when retrieving context. ## How Search Works at Runtime When a user asks a question, the agent doesn't scan every document line by line. It uses semantic search: 1. The user's query is converted into a vector embedding 2. Xpander compares it against all document chunks in the Knowledge Base 3. The closest-matching chunks are injected into the agent's context 4. The agent generates a response grounded in the retrieved content The agent uses a built-in `search_knowledge_base` tool automatically. You don't need to configure this. ## Tuning Relevance Two settings control the quality of search results. Configure these in the Knowledge Base settings. | Setting | What it does | Default | | ------------------------ | ----------------------------------------------------------------------------------------------------------------- | ------- | | **Top K** | How many document chunks to retrieve per query. Higher values give the agent more context but use more tokens. | 5 | | **Similarity Threshold** | How closely a chunk must match the query to be included. Scale of 0.0 (match anything) to 1.0 (exact match only). | 0.7 | If the agent is missing relevant information, increase Top K or lower the threshold. If it's pulling in irrelevant content, raise the threshold or reduce Top K. ## Best Practices * **Write for search, not just for humans.** Semantic search works best when documents have clear headings, self-contained sections, and explicit language. A section titled "Refund Policy" that says "Customers can request a refund within 30 days" will surface much better than one buried in a 50-page PDF with no headings. * **Keep documents focused.** One well-organized document per topic outperforms one massive document covering everything. Split large files into logical sections before uploading. * **Use descriptive names.** Clear Knowledge Base names help you understand which one to query when you have multiple attached to an agent. * **Update regularly.** Knowledge Bases aren't set-and-forget. When your source documents change, re-upload them so the agent stays current. ## Next Steps How your agent remembers across conversations Give your agent actions beyond conversation Test Knowledge Base retrieval in the chat REST API for programmatic access # Memory & State Source: https://docs.xpander.ai/guides/agents/memory-state Control what your agent remembers within conversations, about users, and across all interactions Memory is what separates a useful agent from a frustrating one. Without it, every message is a blank slate. The agent forgets what you said 30 seconds ago. With the right memory configuration, your agent maintains conversation context, learns user preferences, and builds organizational knowledge over time. Xpander gives you three types of memory, each serving a different purpose. Configure them in the **Memory** tab of the Agent Studio. Memory tab showing session storage, user and agent memories, compression, and optimization settings This page covers: * [Session Storage](#session-storage): conversation history within a thread * [User Memories](#user-memories): personal facts about each user that persist across all conversations * [Agent Memories](#agent-memories): global knowledge that applies to all users ## Session Storage Session storage is short-term memory. It keeps the conversation history within a single thread so the agent remembers what was said earlier in the same conversation. Every conversation thread has its own history. As long as messages are in the same thread, the agent sees the full history up to the configured limit. Starting a new thread means a clean slate. The agent won't remember what was said in a previous conversation. Multiple users can share the same thread (e.g., a support ticket where Alice opens the conversation and Bob follows up). Both see the same conversation history, but the thread is still self-contained. Nothing carries over to other threads. Each session storage is associated with one thread. Every session connects a user and the agent, and gets its own isolated storage right beside it. ```mermaid theme={"dark"} graph LR Alice Bob subgraph SG1[" "] direction TB S1["Session 1"] DB1[("Session Storage")] S1 --- DB1 end subgraph SG2[" "] direction TB S2["Session 2"] DB2[("Session Storage")] S2 --- DB2 end subgraph SG3[" "] direction TB S3["Session 3"] DB3[("Session Storage")] S3 --- DB3 end Agent["Support Bot"] Alice --- S1 Alice --- S2 Bob --- S3 S1 ------ Agent S2 ------ Agent S3 ------ Agent style SG1 fill:none,stroke:none style SG2 fill:none,stroke:none style SG3 fill:none,stroke:none ``` | Setting | What it does | Recommendation | | ----------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------- | | **No. of history runs** | How many past runs the agent can see. A *run* is one full agent loop that begins with a user message and ends when the LLM finishes its response. A single run can include many tool calls. | 3–5 for most use cases. 10 if conversations are long and context-heavy. | xpander manages the context window automatically. When usage reaches 80%, the conversation is compacted automatically. Tool call payloads that exceed the context window (or 8k tokens) are auto-truncated. ## User Memories User memories store personal facts about individual users that persist across *all* conversations. When Alice tells your agent "I prefer metric units" in Thread 1, the agent remembers that when she starts Thread 2, Thread 3, or any future conversation. User memories are scoped to `user_id`. They follow the user, not the thread. Each user's memories are completely isolated. Alice's preferences never leak into Bob's conversations, even when they interact with the same agent. This makes user memories safe for multi-tenant environments where personalization matters but privacy is critical. User memory is associated with the user, not with any session or agent. Every session connects a user and the agent, but the memory sits right beside the user and follows them across all sessions. ```mermaid theme={"dark"} graph LR AM[("Alice's User Memory")] --- Alice BM[("Bob's User Memory")] --- Bob Alice --- S1["Session 1"] Alice --- S2["Session 2"] Bob --- S3["Session 3"] S1 --- Agent["Support Bot"] S2 --- Agent S3 --- Agent ``` | Setting | What it does | | ------------------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | **Enable User Memories** | Turns the feature on or off. | | **Agentic managed** | When enabled, the agent decides what to remember automatically. When disabled, memories must be created manually via the `update_user_memory` tool (actions: add, update, delete, clear). | User memories store personal data. Never allow agents to store passwords, API keys, SSNs, or credit card numbers. Memories persist until explicitly deleted. ## Agent Memories Agent memories work like dynamic prompt management. When turned ON, xpander tells the agent to manage memories across each session using markdown files saved in the sandbox environment. This is useful for agent-specific memories that are helpful for all conversations with that agent. For example, "our support hours are 9-5 EST" or "the billing API was updated last week." Agent memory is associated with the agent itself. Every session connects a user and the agent, and the memory sits right beside the agent, shared across every session. ```mermaid theme={"dark"} graph LR Alice --- S1["Session 1"] Alice --- S2["Session 2"] Bob --- S3["Session 3"] S1 --- Agent["Support Bot"] S2 --- Agent S3 --- Agent Agent --- GM[("Agent Memory")] ``` | Setting | What it does | | ------------------- | ---------------------------------------------------------------------------------------------------------------------- | | **Agentic Managed** | When on, the agent manages its own memories as markdown files in the workspace. When off, agent memories are disabled. | Because agent memories affect every user, a single interaction can change behavior for everyone. Not recommended for production, compliance-heavy, or multi-tenant systems without a regular review and rollback strategy. ## Agentic vs. Manual Memory You have two choices for how memories get created and maintained. | | **Agentic Managed** | **Manual** | | ---------------------------- | -------------------------------------------------------- | --------------------------------------------------------------------- | | **How memories are created** | Agent decides what to save automatically | You (or your team) create memories manually | | **Maintenance** | Self-updating, less work for you | Full control, more maintenance | | **Best for** | Internal tools, single-tenant use cases, rapid iteration | Production systems, compliance environments, multi-tenant deployments | | **Risk** | Agent may save inaccurate or unwanted information | Slower to learn, requires ongoing attention | Start with agentic management during development to see what the agent naturally wants to remember, then switch to manual for production with curated memories. ## Memory Optimization These settings help you manage token usage and performance for tool-heavy agents. They appear in the Memory tab in the order listed below. ### Max Tool Calls from History **Deprecated.** xpander now manages tool call retention automatically. This setting will be removed in a future version. Limits how many past tool call results are included when loading conversation history. Set to 0 (disabled) for most cases. Only enable if you're consistently hitting token limits. ### Session Summaries **Deprecated.** This feature will be removed in a future version. Automatically summarizes long conversations into a compact summary for future reference. This does **not** affect the agent's context window. It's metadata for monitoring and observability dashboards. ### Tool Calls Compression **Deprecated.** Tool call compression now happens automatically. You no longer need to configure it. This setting will be removed in a future version. When your agent makes many tool calls in a single conversation, the raw outputs pile up in context and eat through tokens. Tool calls compression condenses verbose outputs after a threshold number of calls. | Setting | What it does | Default | | ---------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------- | ------- | | **Enable compression** | Turns on automatic compression of tool outputs. | Off | | **Threshold** | Number of tool calls before compression kicks in. After N tool calls, summaries replace prior verbose results to keep context within limits. | 3 | | **Compression instructions** | Optional guidance on what to keep vs. drop when compressing. Keep exact numbers, dates, entities, URLs, causal links; remove boilerplate and repetition. | - | ### Memory Optimization Strategy **Deprecated.** This setting will be removed in a future version. Controls how the agent manages its context window during long executions. This is especially useful for agents that handle extended conversations or make many tool calls in a single session. | Mode | What it does | | ----------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | **Disabled** | No optimization. The full conversation history (up to the configured history runs) is included as-is. This is the default. | | **Summarization** | Condenses older messages while preserving key points and tool call results. Reduces token usage while retaining the important context from earlier in the conversation. | | **Context** | Retains the initial instructions and the most recent messages, summarizing everything in between. Best for long-running executions where the beginning (task definition) and end (recent progress) matter most. | ## Troubleshooting Make sure you're passing the same `session_id` for all messages in the thread. Increase history runs to 3+. Verify `user_id` is being passed consistently. Check that User Memories is toggled on. Reduce history runs. Enable tool calls compression. Lower max tool calls from history. Review and delete the memory. Consider switching from agentic to manual management. Agent memories are global. Move user-specific facts to User Memories instead. ## Next Steps Model selection, planning mode, and reasoning mode Give your agent searchable document knowledge Test memory behavior in the built-in chat Full overview of all Agent Studio settings # Testing & Chat Source: https://docs.xpander.ai/guides/agents/testing-chat Test your agent in the Agent Studio and debug its behavior before deploying This page is being phased out. For the current way to interact with and test an agent, see [Build an Agentic App](/guides/omni/agentic-applications/build-your-first-agentic-application) in the User Guide. Before you deploy, run through the checklist below in the Agent Studio chat. Every feature you configured in the previous pages - instructions, tools, knowledge bases, memory, and model settings - should be verified here. You don't need to publish to test. The chat always uses your latest **saved** configuration. Agent Studio with the chat interface and configuration controls ## Testing Checklist Work through each section below. If something isn't working, check the linked configuration page for that feature. ### Instructions and Personality *Your agent should sound like the persona you defined and stay within the boundaries you set.* * **Basic behavior**: Send a few messages and check that the agent responds in the tone, style, and format you defined in your [Instructions](/guides/agents/agent-configuration#instructions). * **Boundaries**: Ask the agent to do something your instructions explicitly forbid. It should decline or redirect - not comply. * **Off-topic handling**: Ask something completely unrelated to the agent's purpose. Verify it stays on topic or deflects the way you intended. ### Tool Usage *Your agent should pick the right tool for the request and pass sensible parameters.* * **Trigger each tool**: For every tool you [attached](/guides/agents/tools-connectors#add-tools-to-your-agent), send a message that should trigger it. Verify the agent picks the correct tool. * **Inspect the tool call**: Click on the tool call in the chat to expand it. Check the tool name, input parameters, raw output, and execution time. This tells you whether a problem is with tool selection, the parameters the agent chose, or the tool itself. * **Tool dependencies**: If you set up [dependencies](/guides/agents/tools-connectors#tool-dependencies), try to trigger the downstream tool directly. The agent should call the prerequisite tool first. * **Ambiguous requests**: Send a message that could match multiple tools. Verify the agent picks the right one. If it doesn't, add tool-specific instructions or reduce the number of enabled tools. ### Knowledge Base Retrieval *Your agent should answer from your documents when relevant and admit ignorance when they don't cover the question.* * **Answerable questions**: Ask questions your [Knowledge Base](/guides/agents/knowledge-bases) documents should cover. Verify the agent's answers are accurate and grounded in your content. * **Unanswerable questions**: Ask something your documents don't cover. The agent should say it doesn't know - not hallucinate an answer. * **Edge cases**: Ask questions that are partially covered or use different phrasing than your documents. If results are poor, adjust the similarity threshold or Top K in your [Knowledge Base settings](/guides/agents/knowledge-bases#tuning-relevance). ### Memory *Your agent should remember what you told it earlier, both in this conversation and across new ones.* * **Within a thread**: Tell the agent a fact ("My timezone is EST") and reference it later in the same conversation. It should remember. * **Across threads**: Start a new thread and check if [User Memories](/guides/agents/memory-state#user-memories) persist. If they don't, verify that User Memories are enabled and that `user_id` is consistent. * **Agent memories**: If you enabled [Agent Memories](/guides/agents/memory-state#agent-memories), verify the agent stores and recalls organizational knowledge across users and threads. ### Multimodal Input *Your agent should read and reason over files you attach alongside your message.* * **Upload supported files**: Send a PDF, image, or audio file and verify the agent processes it correctly. * **Combine text and files**: Send a message with both text and an attachment. Verify the agent uses both in its response. * **Unsupported files**: Upload a file type the agent shouldn't handle. Verify it responds gracefully instead of failing silently. ### Planning and Reasoning *Your agent should break complex tasks into steps and produce deeper answers on hard questions.* * **Planning mode**: If you enabled the [Checklist Toolkit](/guides/agents/ai-models-intelligence#planning-mode), give the agent a multi-step task. Verify it creates a plan and executes steps in order. Check the Monitor tab's **Tasks** view to see the execution plan. * **Reasoning mode**: If you enabled the [Reasoning Toolkit](/guides/agents/ai-models-intelligence#reasoning-mode), ask a question that requires careful analysis. The agent should produce more thorough, well-structured answers than it would without reasoning enabled. ## Set up Error Notifications Get alerted when your agent completes a task or encounters an error. In the Agent Studio **General** tab, expand the **Notifications** section. Notifications are split into two tabs: **Success** and **Error**. Configure them independently - you might want email on errors but webhook on success. Click + next to **Email** or **Webhook** to add a notification channel. * **Email**: Add recipient addresses, and optionally customize the subject line, body, and logo URL. * **Webhook**: Enter a URL to receive a POST payload. Optionally customize the subject, body, logo URL, and add custom headers (or switch to raw JSON). Notifications panel showing Email and Webhook configuration under the Error tab ## Next Steps Publish and connect to Slack, API, SDK, and more Full overview of all Agent Studio settings # Tools & Connectors Source: https://docs.xpander.ai/guides/agents/tools-connectors Browse the connector catalog, authenticate services, and configure tool behavior This page is being phased out. For the current way to give agents tools and data, see [Work with Data and Tools](/guides/omni/building-agents/connectors-skills) in the User Guide. Without tools, your agent can only talk. Tools and connectors let your agent **do things** like sending emails, searching the web, creating calendar events, etc. Xpander has 2,000+ pre-built connectors for popular services like Slack, Google Drive, Salesforce, Jira, GitHub, and more. You can sign in using OAuth or provide API keys to connect your account and let your agent use these services. Connector catalog showing available integrations with connection counts This page covers: * [Create a new connection](#create-a-new-connection): authenticate an external service * [Create a custom connector](#create-a-custom-connector): add your own APIs to the catalog * [Add tools to your agent](#add-tools-to-your-agent): attach specific actions to an agent * [Tool dependencies](#tool-dependencies): enforce tool execution order ## Create a New Connection Before your agent can use a connector, you need to create a **connection**. This authenticates your account with the external service. Each connector can have multiple connections (e.g., different Slack workspaces or different AWS accounts). Open the [Agentic Connectors page](https://chat.xpander.ai/connectors) and choose a connector you want to use (e.g., Calendly, Slack, Google Drive, Salesforce). This opens its **Connector Actions** list. Each action is a tool your agent can call once you've authenticated. You can see all actions grouped by category or as a flat list of API endpoints. Calendly connector actions organized by group Calendly connector showing all 43 individual API actions In the top right of the Connector Actions page, click + Create new connection. Enter connection details: * **Name**: Give the connection a descriptive name (e.g., "Marketing Team Slack") * **Access scope**: * **Personal** (only you can use it), or * **Organization** (anyone in your workspace can use it) Connection creation dialog with authentication method options Select the authentication method based on what the service supports: * Choose **No authentication** for public APIs that don't require credentials * Choose **API Key** for services that use API keys or tokens * Choose **OAuth 2.0** for services with own sign-in flow like Calendly, Slack, Google 1. Select the **No authentication** tab 2. Click **Save** API Key authentication dialog showing auth type and key input fields 1. Select the **API Key** tab 2. Enter your API key or token 3. Choose the auth type: * **Authorization header**: Standard `Authorization` header * **Basic**: Base64 encoded credentials (`Authorization: Basic {encoded}`) * **Bearer**: `Authorization: Bearer {token}` * **In-URL**: Adds the key as a URL query parameter * **Custom**: Define your own header name and format 4. Optionally add custom headers 5. Click Save OAuth 2.0 authentication dialog with Authorize Xpander.ai button 1. Click **OAuth2** and then Authorize Xpander.ai 2. The service's consent screen opens in a new window 3. Review the permissions and click **Approve** OAuth consent screen asking to connect Xpander AI to Calendly **Private OAuth.** If you want to use your own OAuth client ID and secret instead of xpander's shared credentials, contact support and we'll enable and manage private OAuth for you. After creating a connection, you can view and manage all connections for a connector by clicking connections in the top right of the connector's detail page. Connections modal showing saved connections with access scope and version From here you can change the access scope, switch versions, or remove connections. ## Create a Custom Connector If the catalog doesn't have what you need, for example, an internal tool API, you can create your own connector. In the top right of the Connectors Catalog page, click + Create new connector. Connector catalog showing available integrations with connection counts * **Name**: A descriptive name for your connector * **Description**: Optional context about what this connector does * **OpenAPI specification or Postman collection**: Upload a spec file (up to 50 MB) * **API reference URL**: Optional link to your API documentation * **Server URL**: The base URL for your API Create new connector dialog with OpenAPI specification upload Click Create connector. Xpander will turn each endpoint in your API spec into a tool your agent can call. Your custom connector now appears in the catalog. Create a connection to authenticate it (see [Create a new connection](#create-a-new-connection) above), then add its actions to your agents. ## Add Tools to Your Agent Once you've created connections, you can add tools to your agent. Tools come in two types: **Built-in tools** (pre-configured actions) and **Connector tools** (actions from authenticated services). In the [Agents page](https://chat.xpander.ai/agents), select your agent to open its Agent Studio. Agent Studio showing the chat interface and configuration controls Click the **gear** icon in the top right, then go to the **Tools** tab. Agent Tools tab showing built-in tools and Tools section Built-in tools are pre-configured actions that ship with every agent, no authentication or setup required. Click on any tool to toggle it on or off. Click + Add tools to open the connector browser panel. Click Connectors to see the full catalog. Or use the search to find a specific connector. Add tools panel with the Connectors button highlighted
Connector catalog with search and categorized connectors
Click a connector (e.g., Calendly) to see its available connections. Calendly connector showing available connections If you haven't authenticated yet, you'll see **Create new connection**. Click it to set one up (see [Create a new connection](#create-a-new-connection) above). Click an authenticated connection to see its available actions. Check the boxes next to the actions you want. Finally, click + Add to agent to attach them. Selecting specific Calendly actions to add to the agent Fewer tools means fewer decisions for the model, which means better accuracy. Only attach the actions your agent actually needs. The selected actions now appear under the **Tools** section in the config panel. Tools tab showing added Calendly connector tool You'll see a banner: "Deploy changes to update tool configuration." Click **Publish** in the top right to push changes live, or test your draft configuration in the embedded chat first.
## Tool Dependencies Without dependencies, an agent can call any tool in any order. Dependencies lock Tool B until the agent has called Tool A first, even if the user's request only mentions Tool B. This is useful when one tool's output is a prerequisite for another to work correctly. ```mermaid theme={"dark"} graph LR A["Get calendar availability"] --> B["Create calendar event"] ``` Even if the user says "book a meeting at 3pm," the agent must call **Get calendar availability** before it can call **Create calendar event**. This guarantees the agent checks for conflicts before booking. ### Create a dependency Click + Manage dependencies at the top of the Tools tab to open the agent graph, a visual canvas showing every tool attached to your agent as a node. Manage dependencies modal showing the agent graph with tool nodes Click the **top handle** of the tool that must wait (the downstream tool). Drag to the **bottom handle** of the tool it depends on (the upstream tool). The dependency is created automatically. Repeat to build multi-step sequences. You can also create branching paths where multiple tools depend on the same prerequisite, or where a tool requires multiple prerequisites to complete first. ## Configure Max Tool Calls Under **Advanced Configuration** in the Tools tab, you can limit the maximum number of tool calls per run. Advanced Configuration section with the Max tool calls per run limit field Without a limit, an agent with many tools can enter runaway loops, calling tools indefinitely and consuming tokens. Set a cap appropriate for your use case. ## Next steps Upload documents so your agent can search and cite them Planning mode, reasoning mode, and model selection Full overview of all Agent Studio settings Test your tools and debug behavior # Action Nodes Source: https://docs.xpander.ai/guides/building-workflows/action-nodes Run deterministic operations in your workflows: invoke tools from 2,000+ connectors, execute Python code, send emails, extract text with OCR, and more. Action nodes execute fixed operations without an LLM. Seven types are available. **Action nodes vs. agent nodes:** Action nodes execute a fixed operation (API call, code, email) with predictable results. Agent nodes use AI to reason about data, make decisions, and generate output. If the step has a single correct behavior given the inputs, use an action node. If it requires interpretation or judgment, use an agent node. | Node | What it does | Best for | | ------------------- | -------------------------------------- | ----------------------------------------------------------- | | **Action** | Invokes a tool from 2,000+ connectors | Calling external APIs (Salesforce, GitHub, Slack, BigQuery) | | **Code** | Runs Python in a sandboxed editor | Calculations, data transformation, custom logic | | **Email** | Sends an email via a connector | Notifications, confirmations, reports | | **OCR** | Extracts text from images | Processing invoices, receipts, scanned documents | | **Custom Function** | Calls a reusable function you've built | Shared logic across multiple workflows | | **Workflow** | Runs another workflow as a sub-process | Decomposing complex automations into modular pieces | | **Upload File** | Uploads a file to a destination | Storing generated reports, moving attachments | ## Invoke tools from 2,000+ connectors The Action node connects to any of the 2,000+ pre-built connectors (Salesforce, GitHub, Slack, Jira, BigQuery, Google Sheets, Stripe, HubSpot, and more) and executes a specific tool from that connector. Where an Agent node would reason about which tool to call, the Action node calls exactly the tool you select with exactly the inputs you define. When you add an Action node, click **Select Tool** to open the tool browser. It organizes tools into two categories: * **Connectors** lists all 2,000+ integrations alphabetically, each with its available actions. Search by name to find the right one. * **Built-in actions** provides pre-built Xpander functions for common operations that don't require an external connector. Action node tool browser Once you select a tool, write instructions describing what the node should do with its inputs. Use workflow variable placeholders to inject data from previous steps: ```text theme={"dark"} Create a new Jira ticket in the SUPPORT project. Set the summary to the customer's issue description and assign it to the on-call engineer. Priority should match the severity level from the classifier step. ``` After selecting a tool, the **Tool input schema** section in Advanced Configuration populates with the tool's expected input fields. Use this to define or override specific field values rather than relying on instructions alone. The Action node also supports an **Enable stop strategy** toggle in its execution settings. When enabled, the workflow can terminate based on the action's failure conditions rather than propagating bad data downstream. Like other nodes, it supports retry and loop strategies for handling transient failures and iterative processing. ## Run Python code for calculations and transformations The Code node provides a Python editor directly in the workflow canvas. It has syntax highlighting, line numbers, and comes with scaffold code for a handler function. Execution is deterministic with no LLM involved. Two features extend the Code node beyond a basic script runner: **Packages** lets you add pip dependencies (type a package name and it's available at runtime). Need `pandas` for data manipulation or `python-dateutil` for date parsing? Add the package and import it. **Generate with AI** lets you describe what the code should do in natural language, then review and modify the generated implementation. The Code node outputs text by default, but you can change the **Output type** in Advanced Configuration to match what downstream nodes expect. Loop and stop strategies are available for iterative processing and conditional workflow termination. **Code node vs. Agent node for code:** The Code node executes Python you've written (or generated). It's deterministic: same input, same output, every time. If you need an LLM to write and adapt code dynamically at runtime based on varying inputs, use an Agent node with coding tools instead. ## Other action node types The remaining five node types handle specific operations. Each follows the same pattern: select a tool or resource, write instructions, and configure execution strategies in the advanced settings. Sends an email through a connector you choose (Gmail, SendGrid, Outlook, or another email integration). After selecting a tool, the input schema populates with `to`, `subject`, and `body_html` fields. Use workflow variable placeholders to pull values from previous steps. Retry is particularly useful here since transient email delivery failures are common. Extracts text from images and scanned documents. Select an OCR integration, point it at an image via the `file_url` input field, and the node returns extracted text for downstream processing. Pair it with a Classifier or Summarizer to structure the output. Calls a reusable function you've defined outside the workflow. Select a function from the dropdown (or create one with **+ New function**) and write instructions for how it should be used. The **Run asynchronously** toggle fires the function without waiting for a result, useful for side effects like audit logging. Use Custom Functions when the same logic appears in multiple workflows, so updates propagate from a single source. For one-off logic specific to a single workflow, the Code node is simpler. Runs another workflow as a sub-step. Select a workflow from the dropdown (or create one with **+ New workflow**), and its output becomes the input for the next node in the parent. Like Custom Functions, it supports **Run asynchronously** for fire-and-forget operations. Use this when a sequence of steps forms a logical unit that could be tested independently or reused across multiple parent workflows. Moves files to a destination you specify. Write instructions describing what to upload and where, and configure the destination through the tool input schema in Advanced Configuration. ## Choosing the right action node | Decision | Use this | When | | ---------------------------- | --------------- | ----------------------------------------------------------------------------------------- | | **Action vs. Code** | Action | A connector exists for the service and you want managed auth | | | Code | No connector exists, or the operation involves data manipulation beyond a single API call | | **Code vs. Custom Function** | Code | The logic appears in only one workflow | | | Custom Function | The same logic is copied across multiple workflows (updates propagate from one source) | | **Workflow vs. inline** | Workflow node | The steps could be tested, versioned, or triggered independently | | | Inline | The steps only make sense in the context of the current workflow | | **Email vs. Action** | Email node | You need a quick email with standard fields (to, subject, body) | | | Action node | You need more control (templates, attachments, tracking) via a full email connector | ## What's next Branch with conditions, validate with guardrails, pause for human approval, and run steps in parallel. Execute workflows, view results, and debug failed runs. # Agent Nodes Source: https://docs.xpander.ai/guides/building-workflows/agent-nodes Add AI reasoning to your workflows with Agent, Classifier, and Summarizer nodes, each purpose-built for a different kind of intelligence. Agent nodes use an LLM to reason about data, make decisions, and generate output. Three types are available, each designed for a specific kind of reasoning. **Agent nodes vs. action nodes:** Agent nodes use an LLM to reason about data. Action nodes run deterministic operations (API calls, code, email) without an LLM. Use agent nodes when the step requires judgment; use action nodes when the step has a fixed, predictable outcome. | Node | Purpose | Best for | | -------------- | ---------------------------------- | ---------------------------------------------------------------- | | **Agent** | Full AI agent with tool access | Multi-step reasoning, querying systems, making decisions | | **Classifier** | Route inputs to different branches | Intent detection, categorization, triage | | **Summarizer** | Condense or extract from content | Distilling long inputs, extracting key fields, formatting output | ## Reason and act with the Agent node The Agent node connects a full Xpander agent (with its tools, knowledge base, and memory) into your workflow as a single step. When the workflow reaches this node, it hands the input to the agent along with your instructions, and the agent reasons through the task using whatever connectors and knowledge it has access to. ### Configure an Agent node Agent node configuration panel Select an agent from the dropdown. This can be any agent you've built in Agent Studio, arriving with its system prompt, tools, knowledge base, and memory already configured. If you don't have one yet, click **+ New agent** to create one inline. The **Instructions** field tailors the agent's behavior for this specific workflow step. These instructions are appended to the agent's existing system prompt, so you don't need to repeat its general configuration. Focus on what this step should accomplish: ```text theme={"dark"} Enrich the incoming lead with company data. Look up the company in Clearbit and cross-reference with our CRM. If the company has more than 500 employees, flag it as enterprise tier. ``` Use `{{variable}}` placeholders to inject data from previous workflow steps. Click the **Workflow variable placeholders** helper to see what's available. **Persist memory thread** is on by default, meaning the agent reuses the same memory thread across workflow runs and builds up context over time. Turn it off when each run should start fresh. **Run asynchronously** fires the agent without waiting for its response, useful for side effects (like logging) that shouldn't block the workflow. **Output type** controls the format returned: text by default, structured output (JSON to a schema), or voice for audio-enabled agents. ## Route inputs with the Classifier node The Classifier node reads input, evaluates it against criteria you define, and sends it down the matching branch. Unlike keyword matching or regex rules, the Classifier uses an LLM to understand intent. "I can't log in and I've been charged twice" routes to billing, not authentication, because the Classifier understands that the core issue is the charge. ### Configure a Classifier node Classifier node with groups and canvas branches The Classifier works through **groups**. Each group defines a category with evaluation criteria, and each group becomes a separate output branch on the canvas. You start with two groups: **Group 1** (which you should rename) and **Other**. The Other group is a fixed catch-all for anything that doesn't match your defined groups. It cannot be deleted. For each group, write natural language **Evaluation Criteria** describing what qualifies: ```text theme={"dark"} Group: Billing Evaluation Criteria: The input relates to charges, payments, invoices, refunds, subscription changes, or pricing questions. ``` ```text theme={"dark"} Group: Technical Support Evaluation Criteria: The input describes a bug, error, system outage, integration failure, or requests help with configuration. ``` Click **+ Add Group** to create additional categories. Each new group adds another output branch on the canvas, letting you wire different downstream logic for each category. The **Auto-extract relevant data** checkbox (on by default) tells the Classifier to pull out the data points relevant to the matched group and pass them downstream. The next node receives a focused extraction, not the raw input. The Classifier has its own **LLM settings** in the advanced configuration, independent of any agent. You can choose a fast, inexpensive model for classification while reserving a more capable model for complex reasoning in Agent nodes. The **Additional instructions** field lets you add examples or edge case guidance ("When the input mentions both billing and technical issues, prioritize billing"). ## Condense and extract with the Summarizer node The Summarizer node distills large inputs (full API responses, long documents, multi-message histories) into what the next step needs. Beyond simple condensation, you can instruct it to extract specific fields, reformat data, or highlight only the changes since the last run. Summarizer node configuration panel ### Configure a Summarizer node The Summarizer has no agent to select and no groups to define, just an **Instructions** field where you describe what to do with the input. The default instruction is "Summarize the input content," but you'll almost always want to be more specific: ```text theme={"dark"} Extract the customer name, account ID, issue category, and severity level. Ignore the conversation metadata and internal routing information. ``` ```text theme={"dark"} Compare this report against the previous run's output. List only the metrics that changed by more than 10%. ``` Like the Classifier, the Summarizer has independent **LLM settings** where you can choose a lighter model, since summarization is less demanding than multi-step reasoning. **Summarizer node vs. Output Summarizer:** The Summarizer node lives in the middle of your workflow as a processing step between other nodes. The Output Summarizer is part of the END block and formats the final result. Use the Summarizer node when an intermediate step produces too much data for the next step. Use the Output Summarizer when you want to control how the workflow's final result is presented. ## What's next Deterministic operations: tool invocations, code, email, and OCR. Conditions, guardrails, wait gates, and nested workflows. # Agentic Context Source: https://docs.xpander.ai/guides/building-workflows/agentic-context Persist data between workflow runs so each execution builds on the last. Process only what changed, track evolving state, and make smarter decisions over time. Agentic context persists data between workflow runs, so each execution can read what previous runs saved and write data for future ones. The workflow becomes stateful across its entire lifecycle, not just within a single execution. Without agentic context, every run starts from zero with no knowledge of what it previously processed, extracted, or decided. **Agentic context vs. agent memory:** Agents have their own memory system (session storage, user memories) that persists across conversations. Agentic context is a workflow-level feature that persists data between workflow *runs*. Agent memory tracks user preferences across chat sessions. Agentic context tracks what a workflow processed yesterday so it only handles new records today. ## Enable cross-run memory Agentic context is controlled by a toggle in your workflow's settings. Click the **Settings** gear icon in the top toolbar and look for the **Agentic Context** section. The toggle is on by default for new workflows. When enabled, every node with a Context Input field set automatically receives two values from the previous execution: the **last run datetime** and the **last run result**. Agentic context in workflow settings Turning the toggle off disables cross-run state entirely. Every run becomes independent. ## Configure what each node remembers The workflow-level toggle is the on/off switch. The node-level configuration controls what data flows in and out of the agentic context. You'll find **Context Input** and **Context Output** in the **Advanced Configuration** section of most node types, under the **Agentic context** heading. **Context Input** describes what previously saved data to inject into this step. Write a natural language description of what the node needs from prior runs: ```text theme={"dark"} Inject the list of ticket IDs that were processed in the previous run, along with the timestamp of the last processed ticket. ``` When you set a Context Input description, the node automatically receives the last run datetime and last run result alongside whatever specific data you describe. The description tells the AI what to look for in the stored context and how to incorporate it. **Context Output** describes what data from this step's response to save for future runs: ```text theme={"dark"} Save the list of newly processed ticket IDs and the highest-priority issue category found in this batch. ``` The data you describe gets persisted after the run completes. The next time the workflow executes, any node with a matching Context Input description can access it. Agentic context fields in node configuration ### Which nodes support agentic context | Supports agentic context | Does not support agentic context | | ---------------------------------- | -------------------------------- | | Agent, Classifier, Summarizer | Condition | | Action, Code, Email, OCR | Parallel | | Custom Function, Workflow (nested) | Send to End | | Wait, Guardrail | | Condition nodes evaluate a simple comparison that doesn't benefit from historical context. Parallel nodes orchestrate concurrent execution and don't process data themselves. Send to End nodes pass a finish message, so there's nothing to persist. ## Detect what changed since the last run The most common use of agentic context is delta detection: comparing the current run's data against the previous run and acting only on the differences. Set the Agent node's Context Input to "Inject the timestamp and ticket IDs from the last run." The node uses the last run datetime to filter results to only records created after that timestamp, and cross-references against saved IDs to skip anything already processed. The Context Output saves the current timestamp and processed IDs for next time. Delta detection is not limited to timestamps. You can save and compare: * Record IDs to skip already-processed items * Computed values like a pipeline total so the next run can report the change * Accumulated state like an unresolved discrepancy list that carries forward until resolved ## Write effective context descriptions The Context Input and Context Output fields accept natural language, so their effectiveness depends on how clearly you describe what to save and retrieve. **Be specific about the data, not the mechanism.** Write "Save the customer email, sentiment score, and ticket category from this analysis" rather than "Save the output." The AI needs to know which pieces of the step's result matter for future runs. **Match your input descriptions to your output descriptions.** If one node's Context Output saves "the list of processed order IDs and the highest order value," a downstream node in a future run should have a Context Input that asks for those same items. Mismatched descriptions mean the AI may not retrieve the right data. **Start simple.** Save one or two values (a timestamp and a list of IDs) first. Once you've confirmed the cross-run behavior works, expand to more sophisticated state like trend comparisons or running averages. ## What's next Manage immutable deploy snapshots and roll back to previous workflow versions. Execute workflows, view results in the output console, and debug failed runs. # Workflow Canvas Source: https://docs.xpander.ai/guides/building-workflows/canvas Add nodes, wire them into a pipeline, and use the save-and-publish cycle to deploy versioned workflows. The canvas is the workspace where you build workflow pipelines. Triggers on the left, processing logic in the middle, outputs on the right. This page covers placing nodes, testing, and the save-and-publish cycle. **Canvas vs. node configuration:** This page covers the canvas workspace. For configuring individual node types (writing instructions, selecting tools, setting up classification groups), see [Agent Nodes](/guides/building-workflows/agent-nodes), [Action Nodes](/guides/building-workflows/action-nodes), and [Flow Control](/guides/building-workflows/flow-control). ## Canvas layout Every workflow flows left to right: a **START block** on the left, an **END block** on the right, and a purple connection line between them. Events enter from the left, pass through each node in sequence, and exit as output on the right. Workflow canvas layout The **START block** stacks five trigger types vertically (Webhook, API, Chat, Slack, Schedule). Each row shows a green dot when enabled and a badge below counts active triggers ("3 events"). The **END block** stacks three output options: * A **Summarizer** for natural language digests * A **JSON Object** for structured data against a schema * **Notifications** for emails or webhooks on success or failure When a node branches (Classifier, Condition, Guardrail), the canvas expands vertically to show parallel paths, but the left-to-right direction stays the same. ## Add nodes Click the **+** button on any connection line to open the node picker. It organizes 15 node types into three categories. **Agents** use AI to reason about data: | Node | What it does | | -------------- | ------------------------------------------------------- | | **Agent** | Full AI agent with tool access for multi-step reasoning | | **Classifier** | Routes inputs to different branches based on meaning | | **Summarizer** | Condenses or extracts from content | **Actions** run deterministic operations without an LLM: | Node | What it does | | ------------------- | ----------------------------------------------------------------- | | **Action** | Invokes a connector tool (Salesforce, GitHub, Slack, 2,000+ more) | | **Workflow** | Nests a separate workflow as a sub-process | | **Custom Function** | Executes a custom function you've defined | | **Code** | Runs Python for calculations and transformations | | **Email** | Sends an email | | **OCR** | Extracts text from images | | **Upload File** | Uploads a file to a destination | **Flow** nodes control branching and execution: | Node | What it does | | --------------- | ------------------------------------------------------------------ | | **Condition** | Splits flow based on values (contains, equals, regex, comparisons) | | **Guardrail** | AI judge that validates output as Pass or Fail | | **Wait** | Pauses for human approval before continuing | | **Send to End** | Finishes the workflow immediately | | **Parallel** | Runs child nodes concurrently and combines results | | **Schedule** | Can schedule runs on new/existing nodes at a set frequency | Add node dropdown Clicking a node type inserts it at that position. A configuration panel opens on the right where you write instructions, select tools, or define conditions. Every connection line between nodes has its own **+** button, so you can insert steps anywhere in the pipeline without rebuilding the flow. Branching nodes (Classifier, Condition, Guardrail) automatically create output branches. A Classifier with "Billing," "Technical Support," and "Other" groups fans out into three branches, each with its own **+** buttons for adding downstream logic. ## Test workflows The top toolbar has a green **Run** button labeled with the active test preset name (e.g., "Hello World"). Click the gear icon next to it to configure your test payload: plain text or JSON, with optional file attachments. Save named presets so you can re-run the same test cases quickly. When a test starts, the **Output Console** appears at the bottom of the canvas showing real-time execution events: task creation, tool requests, tool results, and the final outcome. Click any entry to expand the full JSON payload. Test input and output console If your workflow handles different input shapes, create a preset for each one and cycle through them before publishing. The top toolbar also has **Builder** and **Monitor** tabs. Builder is the canvas. Monitor shows execution history, logs, and metrics after the workflow has run. ## Save and publish Changes are not saved automatically. When you modify anything, a floating toolbar appears at the bottom with **Undo**, **Reset**, and **Save**. It disappears once you save or reset. Floating save toolbar Saving stores your changes but does not deploy them. The live version that triggers run against stays unchanged until you publish. This lets you iterate without affecting production traffic. The cycle: 1. Make changes on the canvas 2. **Save** using the floating toolbar 3. The **Publish** button in the top toolbar turns purple with a red dot 4. Click **Publish**, confirm the dialog, and the new version goes live Each publish creates a new live version. All triggers (webhooks, schedules, API calls) immediately execute against it. If something goes wrong, you can roll back to a previous version. The platform keeps immutable snapshots of every published version. **Save vs. Publish:** Save is a checkpoint. Publish is a release. Save frequently as you work. Publish when the workflow is ready for production traffic. You can save many times between publishes, but only a publish pushes changes to the live version. ## What's next Configure webhooks, schedules, API calls, and other trigger types in the START block. Add AI-powered reasoning steps that query systems, classify inputs, and summarize results. Run deterministic operations: tool invocations, code, email, and OCR. Branch with conditions, validate with guardrails, and pause for human approval. # Flow Control Source: https://docs.xpander.ai/guides/building-workflows/flow-control Branch on values, validate with AI, pause for human approval, finish early, run steps in parallel or schedule runs at a set frequency. Flow control nodes handle branching, validation, gating, and parallel execution. Six types are available. **Flow control vs. Classifier:** The Classifier node (covered in [Agent Nodes](/guides/building-workflows/agent-nodes)) also branches a workflow, but it uses an LLM to understand the *meaning* of the input. Condition nodes branch on explicit data values. Use Classifiers for intent-based routing, Conditions for value-based branching. ## Branch on data values with Conditions The Condition node splits your workflow into two paths based on a test you define: an IF branch for inputs that match, and an ELSE branch for everything that doesn't. ### Configure a Condition node The Condition node opens as a floating dialog instead of a side panel. Condition node floating dialog Configuration happens in two steps. **Step 1** asks you to define the condition. Pick a **Condition Type** from the dropdown and enter a **Term** (the value to test against). The term field supports `{{variable}}` placeholders to reference data from previous workflow steps. Click **Next** once defined. **Step 2** asks you to select the target node type for the IF branch, the node that runs when the condition matches. The ELSE branch connects to whatever comes next in the default flow. Once placed on the canvas, clicking the IF branch opens an **Edit Condition** panel where you can change the condition type and term without rebuilding the node. ### The nine condition operators | Category | Operator | What it checks | | ----------------- | ----------------------- | ------------------------------------------ | | **Text matching** | Contains | Input includes the term as a substring | | | Regex | Input matches a regular expression pattern | | **Comparison** | Equal (`==`) | Input exactly matches the term | | | Not Equal (`!=`) | Input does not match the term | | | Greater Than (`>`) | Input is numerically greater than the term | | | Less Than (`<`) | Input is numerically less than the term | | | Greater or Equal (`>=`) | Input is greater than or equal to the term | | | Less or Equal (`<=`) | Input is less than or equal to the term | | **Existence** | Not Empty | Input has any value (term is not required) | Contains is the default. Switch to comparison operators for numeric thresholds, or use Regex for pattern matching more expressive than simple substring search. ## Validate output with Guardrails The Guardrail node uses an AI judge to evaluate upstream output against criteria you define, then routes it down a **Pass** or **Fail** branch. Unlike the Condition node, which tests against fixed values, the Guardrail evaluates quality and correctness using natural language criteria. ### Configure a Guardrail node The Guardrail opens as a side panel with two fixed groups: **Pass** (green checkmark) and **Fail** (red circle). You cannot add or remove groups. Every Guardrail is a binary pass/fail gate. For each group, write **Evaluation Criteria** in natural language: ```text theme={"dark"} Pass criteria: The response includes a specific dollar amount, references the customer's account ID, and does not promise anything outside our standard refund policy. Fail criteria: The response is vague about the refund amount, references a different customer's information, or makes commitments that exceed our refund policy limits. ``` The **Auto-extract relevant data** checkbox (on by default) tells the Guardrail to pull out the data points that informed its decision and pass them downstream. The next node receives a focused extraction, not the raw input. Guardrail node configuration panel The Guardrail has its own **LLM settings**, independent of any agent in your workflow. You can choose the provider and model. A capable model like Claude Sonnet 4.6 works well for nuanced quality checks, while simpler pass/fail criteria might work with a lighter model. Use the **Additional instructions** field and **+ Add example** button to provide sample inputs with expected outcomes, which improves evaluation accuracy on edge cases. ## Pause for human approval with Wait The Wait node pauses the workflow and sends a notification to a person (or group) to approve or deny before execution continues. The recipient gets an email with context and two buttons: **Approve** (resumes the workflow) and **Deny** (stops it). Wait node configuration panel The notification defaults to **Email**. Add recipients, customize the subject and body (using `{title}` and `{content}` placeholders for workflow context, or `{{variable}}` for data from previous steps), and optionally relabel the approve/deny buttons. A **Webhook** notification option is also available for routing approvals to your own system (an internal dashboard, a ticketing tool, or a custom approval system) instead of email. ## Stop the workflow early with Send to End Send to End node panel The Send to End node immediately finishes the workflow from wherever it sits in the flow. The only configuration is an optional **Finish Message** that becomes the workflow's output. If left empty, the workflow returns whatever the previous step produced. If your END block has output nodes configured (a Summarizer or JSON output), the workflow routes through those nodes before finishing. Send to End triggers the endgame but respects the output pipeline you've defined. ## Run steps concurrently with Parallel The Parallel node runs its child nodes concurrently and combines their results before passing them to the next step. Click **+ Add node** to add branches. All branches receive the same input and execute simultaneously. Parallel node configuration panel ## Schedule runs with the Schedule node The Schedule node resumes a workflow at a defined time or frequency. When triggered, it routes execution to any target node you choose - an Agent, Classifier, Condition, Summarizer, Custom Action or any other node in the workflow. Image Configure it with two fields: * **When** - a free-text time expression (e.g. "in 1 hour", "next Monday 9am", "tomorrow 14:00") * **Target Node** - the node to resume execution at when the schedule fires ## Choosing the right flow control node | Node | What it does | Decision made by | Branches | | --------------- | ------------------------------------------------------- | ------------------------------------------------------------- | ----------------------------- | | **Condition** | Splits flow based on a data test | Deterministic operator (contains, equals, greater than, etc.) | IF / ELSE | | **Guardrail** | Validates output quality | AI judge evaluating natural language criteria | Pass / Fail | | **Wait** | Pauses for human review | A person clicking Approve or Deny | Continues or stops | | **Send to End** | Terminates the workflow early | Placement in the flow (always fires) | None (workflow ends) | | **Parallel** | Runs steps concurrently | Placement in the flow (always fires) | N concurrent branches | | **Schedule** | Resumes the workflow at a target node on a set schedule | A time expression (e.g. "in 1 hour", "next Monday 9am") | None (resumes at target node) | Conditions test data values ("is this number above 500?"). Guardrails evaluate quality ("does this response meet our standards?"). If you can write the check as a comparison operator, use a Condition. If you need an LLM to judge whether something passes, use a Guardrail. Wait and Guardrail both act as gates, but with different reviewers. A Guardrail uses AI for fast, consistent checks you can describe in criteria. A Wait node requires a human, necessary when regulations, contracts, or organizational policy demand a person sign off. Use a Schedule node when you need a part of your workflow to run automatically at a future time or recurring interval, without any manual trigger. ## What's next Persist state across workflow runs for delta detection and cross-run intelligence. Save immutable snapshots of your workflow and roll back to previous versions. # Introduction to Workflows Source: https://docs.xpander.ai/guides/building-workflows/introduction Backend automation where AI handles data mapping at runtime. Trigger with webhooks, schedules, emails, or API calls. Workflows are backend automation pipelines that use AI to resolve data mapping at runtime. Each step is described in natural language, so the automation adapts when an API restructures its response or a field gets renamed, without manual rewiring. ```text theme={"dark"} # Traditional automation (brittle) Step 1: GET /api/enrich → map response.company.size to lead.company_size Step 2: IF lead.company_size > 500 → map to enterprise_pipeline Step 3: POST /salesforce/lead → map 12 fields individually # Agentic automation (intent-based) Step 1: "Enrich this lead with company data from Clearbit" Step 2: "Route enterprise leads (500+ employees) to enterprise pipeline" Step 3: "Update the lead in Salesforce with the enrichment results" ``` AI nodes understand intent and resolve mapping themselves. Action nodes that need deterministic execution (sending an email, running a SQL query) run without an LLM. You get AI reasoning where it helps and predictable execution where it matters. **Workflows vs. agents:** Agents handle conversations through Slack, Teams, or a chat widget. Workflows handle backend automation triggered by events, with no chat interface. If a human is typing messages, you want an agent. If an event should kick off a process automatically, you want a workflow. ## The canvas Every workflow is built on a horizontal canvas that flows left to right: a **START** block, an **END** block, and your logic in between. Add nodes by clicking the **+** button on the connection line. Workflow canvas overview The **START block** stacks five trigger types vertically. You can enable multiple triggers on the same workflow so the same process fires from different sources. | Trigger | What starts the workflow | | ------------ | ----------------------------------------------------------------------------------- | | **Webhook** | An HTTP POST from an external system (Stripe payment, GitHub push, form submission) | | **API** | A REST call from your own application code | | **Chat** | A message sent through a web chat interface | | **Slack** | A message in a Slack channel or DM | | **Schedule** | A recurring cron schedule (every 5 minutes, daily at 9am, weekdays only) | Between START and END, **nodes** handle processing in three categories. **Agent nodes** use AI to reason about data: an Agent queries connected systems and makes decisions, a Classifier routes inputs to branches based on intent, and a Summarizer condenses large inputs into structured output. **Action nodes** run without an LLM for fast, deterministic execution: invoking any of the 2,000+ connectors (Salesforce, GitHub, Slack, BigQuery), sending emails, extracting text with OCR, running Python code, or nesting a workflow as a sub-process. **Flow control nodes** handle branching and validation: conditions split the flow, guardrails use an AI judge to validate output, wait nodes pause for human approval, and parallel nodes run independent branches simultaneously. The **END block** offers three output options. * A **Summarizer** generates a natural language digest of everything the workflow processed. * A **JSON Object** returns structured data against a schema you define (or generate with AI) for downstream systems that need a predictable format. * **Notifications** send emails or webhooks on success or failure. ## When to use workflows Workflows fit when a process should run automatically in response to an event, without a human in the conversation loop: * A Stripe webhook fires, kicking off invoice reconciliation across your ERP and billing system * A daily schedule enriches new leads overnight and updates Salesforce * An inbound email gets parsed, classified by urgency, and routed to the right support queue in Jira * A GitHub push triggers compliance scanning, and a guardrail node blocks deployment if PII is detected ## What's next Navigate the canvas, add and connect nodes, save and version your work. Configure webhooks, schedules, API calls, and other trigger types. Use AI to reason about data, classify inputs, and summarize results. Invoke tools, send emails, run code, and execute deterministic operations. # Running & Monitoring Source: https://docs.xpander.ai/guides/building-workflows/running-monitoring Test workflows with text or JSON payloads, watch execution in real time, and monitor threads, metrics, and tasks in production. The test panel and output console provide visibility during development. The Monitor tab provides the same for production traffic. ## Test a workflow from the canvas The top toolbar includes a green play button labeled with the active test preset name (the default is "Hello World"). Click the play button to run the workflow with the current test configuration. Click the gear icon next to it to open the test configuration panel. ### Input modes The test panel has two input modes, toggled by a switch at the top. **Text mode** is a plain text area. Type a message and hit run. This is the fastest way to test. **JSON mode** switches to a structured JSON editor for payloads that match what a webhook or API call would send. Use this when your workflow's logic depends on specific field names or nested data structures. Below the input field, an expandable **Files** section lets you drag and drop or browse to upload files for workflows that process documents (OCR nodes, agent analysis, compliance scanning). ### Test presets The test panel includes a name field and a **Save as Preset** button that saves the current input as a named preset. Saved presets appear in the play button's label, so you can switch between scenarios without reopening the panel. ## Read results in the output console When you run a workflow, the **output console** appears at the bottom of the canvas and streams events in real time. Events appear as they happen, so you can watch a multi-step workflow progress through its nodes. Each event shows a timestamp, event type, duration, and status: | Event | What it means | | --------------------- | ----------------------------------------------------------------------------------------- | | **Task Created** | The workflow run has started. A new task was created from your test input. | | **Tool Request** | A node is calling an external tool or connector. Shows which tool and what data was sent. | | **Tool Result** | The tool call completed. Shows the response data returned. | | **Workflow Finished** | All nodes have executed. Shows final status and total duration. | Clicking any event row expands the full JSON payload, so you can inspect exactly what data flowed between steps. Copy buttons on each payload make it easy to grab a result for comparison. The console toolbar includes: * **Run Again** to re-execute with the same input after making changes * **Search events** to filter a long event list * **Clear** to reset the console * **Expand** for full-screen view During an active run, a **Stop** button lets you cancel early. The status bar at the bottom shows the timestamp of the last test run. **Output console vs. Monitor tab:** The output console shows events from test runs you trigger from the canvas. The Monitor tab (covered next) shows data from all runs, including production traffic from webhooks, schedules, and API calls. Use the console while building. Use the Monitor tab once the workflow is live. ## Monitor production runs Once your workflow is published and handling real traffic, switch from **Builder** to **Monitor** using the toggle in the top toolbar. The Monitor tab has three sub-tabs: Threads, Metrics, and Tasks. ### Threads: trace a specific run The Threads view lists every conversation session your workflow has handled. Each row shows the thread ID, trigger type (Chat, Webhook, API), the input that started the run, and when it last executed. Click any thread to open its **log panel**, which reconstructs the full execution timeline step by step. The log header shows total execution duration down to the millisecond, and a **Download Log** button lets you export the full log for offline analysis. The timeline shows each step in order: the input message, each node's request and response payloads, and the final output. Use this to trace which node produced an unexpected result. On the right side of the log panel, an **AI Insights** section with an **Evaluate** button uses AI to analyze the execution and surface observations you might miss when reading raw payloads. ### Metrics: track resource consumption The Metrics sub-tab shows five bar charts, each filterable by date range: | Chart | What it tracks | | ---------------------------- | ------------------------------------------- | | **Requests** | Workflow runs per day | | **Outbound API calls by AI** | External API calls agent nodes made per day | | **Input tokens** | Tokens sent to LLMs per day | | **Output tokens** | Tokens generated by LLMs per day | | **Total tokens** | Combined input and output tokens per day | The requests chart tracks workflow activity. The API calls chart helps spot unexpected spikes from loops or misconfigured nodes. The token charts help track LLM costs and identify optimization opportunities, like switching a summarization step to a lighter model. ### Tasks: find runs by status The Tasks sub-tab provides a flat list of every individual execution, regardless of which thread it belongs to. Each row shows the task ID, creation and update timestamps, and current status (Completed, Failed, or Running). Filter or scan for tasks with a **Failed** status, then cross-reference the task ID in the Threads view to see the full execution log and diagnose what went wrong. ## What's next Publish workflow versions and roll back when a change causes problems. Configure how workflows start: webhooks, API calls, schedules, and more. # Triggers Source: https://docs.xpander.ai/guides/building-workflows/triggers Configure how workflows start: via webhooks, API calls, chat messages, Slack, or recurring schedules. Triggers define how a workflow starts. Five types are available, and you can enable multiple triggers on the same workflow so the same process fires from different sources. **Triggers vs. notifications:** Triggers *start* a workflow. Notifications (configured in the END block) *send alerts when a workflow finishes*. Both can use webhooks, but they serve opposite ends of the pipeline. ## Configure a trigger Triggers live in the **START** block on the left side of the canvas. Each trigger type appears as a row with a green dot when active and a chevron to open its configuration panel. The badge below the block counts active triggers (e.g., "3 events"). START block with trigger rows ## Start workflows from external events with webhooks Any service that can send an HTTP POST (Stripe, GitHub, Jira, your own backend) can trigger a run. Open the Webhook trigger panel to see a unique URL. Copy it into your external service's webhook configuration. Every POST to that URL starts a new run with the request payload as input. The URL follows this pattern: ``` https://webhook.xpander.ai?agent_id={workflow-id}&x-api-key={key}&agent_version=1 ``` The panel also includes a **Test Webhook** button to fire a test request from the UI and a **View Docs** link for payload formatting details. ## Invoke workflows programmatically with the API trigger The API trigger provides a REST endpoint for starting runs from your own application code. The panel shows your **Workflow ID** (with a copy button), a **Test API** button that opens an in-browser tester, and a **View Docs** link. ### The API tester Clicking **Test API** opens a modal where you can construct and send requests without leaving the canvas. It provides the full endpoint URL, your API key, and a pre-generated cURL command. Three invocation modes are available: * **Synchronous** (wait for the result) * **Asynchronous** (fire and forget) * **Stream** (server-sent events) A key/value editor at the bottom lets you build JSON payloads field by field. After sending a request, the **Response History** tab shows results so you can iterate without switching tools. Workflow API tester ## Let users trigger workflows through chat The Chat trigger provides a hosted web interface at a URL like `https://{name}.agents.xpander.ai`. Share that URL with anyone who should be able to start the workflow. The interface supports multi-turn conversation, file attachments, and voice input. **Chat trigger vs. agent chat:** Agents built in Agent Studio also have chat interfaces, but those are designed for open-ended conversation. A workflow's chat trigger feeds messages into a structured pipeline with defined steps, branching logic, and deterministic actions. Use it when you want the structure of a workflow with the accessibility of a conversation. ## Connect workflows to Slack The Slack trigger lets a bot start your workflow from channels and direct messages. The panel shows a connection status and a **Connect to Slack agent** button. Once connected, messages sent to the bot (or mentions in a channel) trigger runs with the message content as input. ## Run workflows on a schedule Click **+ Add Schedule** to configure a time-based trigger. The schedule modal has two parts. **Instructions** describe what the workflow should process on each run. Since there's no incoming payload, this is where you provide context (e.g., "Pull all new support tickets from the last 24 hours"). The **schedule** controls when it runs. Two scheduling modes are available: **Interval mode** sets a repeating cadence. Specify a frequency (every 5 minutes, every 2 hours), then toggle which days of the week the schedule should run. The minimum interval is 5 minutes. **Specific Time mode** targets exact times of day rather than repeating intervals. A **Cron preview** below the controls shows the generated expression (e.g., `*/5 * * * *`) so you can verify the schedule. **Quick Presets** offer common schedules, and **Advanced Settings** exposes additional tuning options. Schedule trigger configuration ## Choosing the right trigger | Trigger | Input source | Starts when | Good for | | ------------ | ------------------------- | ----------------------------------- | --------------------------------------------------- | | **Webhook** | HTTP POST payload | External system sends a request | Reacting to events in third-party services | | **API** | JSON payload via REST | Your application calls the endpoint | Programmatic invocation from your own code | | **Chat** | User message | Someone types in the chat UI | Human-initiated processes with conversational input | | **Slack** | Slack message | Someone messages the bot | Team-accessible workflows without leaving Slack | | **Schedule** | Instructions (no payload) | Cron timer fires | Recurring jobs: reports, syncs, audits | All five trigger types feed into the same pipeline: same nodes, same logic, same output configuration. The only difference is how and when the run starts. ## What's next Add AI-powered steps that reason about data, classify inputs, and summarize results. Run deterministic operations: tool calls, emails, code execution, OCR. # Versioning & Rollback Source: https://docs.xpander.ai/guides/building-workflows/versioning Publish-based versioning that separates editing from deploying. Save drafts, publish immutable snapshots, and roll back when needed. Xpander uses publish-based versioning: you save your work as a draft, test it, and only push it live when you explicitly publish. The running workflow stays on its last published version until you say otherwise. **Save vs. publish:** Saving persists your changes so you don't lose work, but it does not affect the live workflow. Publishing creates a new immutable version that replaces the current live deployment. Save is "checkpoint my progress." Publish is "ship it." ## Track unsaved changes on the canvas When you modify anything on the canvas (add a node, change an instruction, reconfigure a trigger), Xpander signals unsaved changes in two places. A **floating toolbar** appears on the canvas with three actions: * **Undo** reverses the last change * **Reset** discards all unsaved changes and reverts to the last saved state * **Save** persists your changes as a draft without affecting the live workflow At the same time, the **Publish** button in the top toolbar picks up a red notification dot, signaling saved work that hasn't been deployed yet. If you try to navigate away with unsaved changes, Xpander prompts with a "Discard Changes?" dialog. ## Publish your changes Click **Save** on the floating toolbar (or the save icon in the Settings panel) to persist your draft. The floating toolbar disappears, but the Publish button stays active with its red dot. When you're ready to go live, click the **Publish** button. A confirmation dialog appears: "Publish Changes? This will publish your changes and make them live. This action cannot be undone. Proceed?" Click **Confirm** to deploy. The red dot clears, the Publish button grays out, and your workflow is now running the new version. This two-step flow lets you save frequently without disrupting production, make changes across multiple editing sessions, and only publish once everything is ready. The workflow keeps running its last published version the entire time. ## Understand immutable snapshots Each publish creates an immutable snapshot of the entire workflow: every node, connection, instruction, and trigger configuration. This snapshot cannot be modified after publication. Further edits create a new draft that becomes the next snapshot when you publish again. This guarantees that what you tested is exactly what's running. There's no risk of a partial edit leaking into a live version. The webhook URL includes a version parameter (`agent_version=1`) so external systems can reference a specific published version. ## Roll back to a previous version Each publish creates an immutable snapshot, so rolling back means redeploying an earlier snapshot as the active version. Previous versions are preserved: publishing a new version doesn't delete old ones. ## What's next Run your published workflow and monitor execution results. Navigate the canvas, add and connect nodes, and manage your workflow layout. # Core Concepts Source: https://docs.xpander.ai/guides/core-concepts Understand the fundamental concepts behind Xpander These concepts still apply. For the current way to build with xpander and how they map to the new experience, refer to [Welcome to Omni](/guides/omni/what-is-omni) and [Agentic Applications](/guides/omni/agentic-applications/what-are-agentic-applications) in the User Guide. This page covers the building blocks of xpander: agents, workflows, multi-agent teams, tools, and how they connect. Read this before diving into the detailed configuration guides. ## Workbench The Workbench is where you build and monitor your agents. It has two views: * **Builder**: configure your agent's personality (SOUL), tools, and channels. Click the gear icon in the top right to open the configuration panel. * **Monitor**: inspect conversation logs, track tool usage, and view performance metrics. You'll spend most of your time in Builder when setting up an agent, and switch to Monitor once it's running to understand how it's performing. xpander Workbench in Builder view showing the chat panel, system prompt editor, and configuration sidebar *** ## Agents Agents are AI applications with memory that follow natural language instructions, use tools, and make decisions autonomously. Behind the scenes, they are powered by LLMs such as OpenAI GPT-5.2, Claude Opus 4, or Gemini 2.5 Pro. You can configure how they respond (text, markdown, JSON, or HTML) and who can access them (just you, or your entire organization). xpander supports five agent types: * **Regular**: (standard) * **Manager**: (coordinates other agents) * **A2A**: (agent-to-agent protocol) * **Curl**: (HTTP-based) * **Orchestration**: (powers workflow nodes). ### Instructions (SOUL) Every agent on xpander has a defined SOUL, short for **System Orchestration & User Logic**. It defines who your agent is and how it behaves through six fields: * **Who I Am**: Identity and self-description * **Core Truths**: Personality traits and behavior principles * **Boundaries**: Constraints the agent must respect * **Vibe**: Communication style and tone * **Continuity**: How the agent treats memory and persistence * **Current Focus**: Current objectives SOUL configuration panel showing the six instruction fields: Who I Am, Core Truths, Boundaries, Vibe, Continuity, and Current Focus ### Memory Agents remember things across conversations through three types of memory: * **Session Storage**: Context within a single conversation thread * **User Memories**: Per-user learned facts and preferences * **Agent Memories**: Long-term knowledge the agent curates over time ### Channels Beyond the xpander web UI, you can interact with agents through several channels: * **API**: REST endpoint for programmatic access * **Slack**: Slack workspace integration * **Telegram**: Telegram bot * **Webhook**: Trigger from external systems * **MCP**: Expose agents to MCP-compatible clients like Claude Desktop and ChatGPT Channels configuration panel showing toggles for API, Slack, Telegram, Webhook, and MCP ### Deployment You can deploy agents in two ways, depending on how much control you need: * **Serverless**: No code. Build in Workbench, runs on managed infrastructure. * **OpenClaw**: Fully managed runtime that powers Personal Agents. IT deploys once, all employees get access. ### Frameworks All agents run on a framework, Agno by default. Using the SDK, you can write custom agent logic in Python with any supported framework: Agno, OpenAI SDK, Google ADK, LangChain, or AWS Strands. *** ## Workflows Workflows are a visual orchestration layer for building multi-step AI pipelines. You arrange agents, tools, and logic on a canvas where data flows left to right, from a START block through processing nodes to an END block. Workflow canvas showing START block, Agent nodes, Action nodes, and END block Every workflow starts with a **START block** that accepts one or more trigger types: * **Webhook**: HTTP POST from external systems * **API**: REST endpoint * **Chat**: Conversational interface * **Schedule**: Cron-based recurring execution Every workflow ends with the **END block** determining how results are returned: Summarizer (AI-generated summary), JSON Object (structured data), or Alert (notifications on failures, completions, or thresholds). In between, you can add nodes of three types: **Agent**, **Action**, and **Flow**. Every node is powered by an AI agent, so there's no field mapping: agents read the previous step's output and act on natural language instructions. All node types have an **Instructions** field where you write a prompt that gets injected into the agent's system prompt at runtime alongside data from previous step/triggers. ### Agent Nodes Agent nodes explicitly invoke AI models to process data. * **Agent**: Runs one of your xpander agents with its full tool set and memory * **Classifier**: Labels or routes data based on natural language instructions * **Summarizer**: Answers specific questions from large payloads ### Action Nodes Action nodes execute tools and integrations. They also use a hidden AI agent to map data automatically, so you don't need to configure any schemas. * **Action**: Picks any tool from the xpander library * **Email**: Composes and sends emails * **OCR**: Extracts text from images and documents * **Code**: Runs custom code (no LLM: the only deterministic node) * **Custom Function**: Runs a reusable pre-defined function * **Workflow**: Nests another workflow as a sub-step ### Flow Nodes Flow nodes control the execution path through the workflow. * **Condition**: Branches into different paths * **Guardrail**: An AI judge that evaluates natural language rules and returns Pass/Fail * **Wait**: Pauses until a condition is met or a human approves * **Send to End**: Skips remaining nodes and exits early ### Agentic Context Workflows can be made stateful across runs using **Agentic Context**. When enabled, xpander stores the last run datetime and result after each execution. Nodes can pull from previous runs via Input Instructions and store data for future runs via Output Instructions. This is different from agent memory, which persists across conversations: Agentic Context persists across workflow runs. ### Deduplication For webhook-triggered workflows, you can enable **Prevent Duplicate Events** to deduplicate incoming requests. You define Event Identifier Fields (JSON paths like `messageId` or `customer.email`) as composite keys, and duplicates within a configured time window are skipped. *** ## Multi-Agent Teams You can create teams of specialized agents that work together to accomplish complex tasks. Three multi-agent coordination patterns: Router directs tasks to the best agent, Sequence chains agents in fixed order with configurable memory handoff, Manager dynamically delegates and monitors There are three coordination patterns: * **Router**: Agents operate independently while a router directs each task to the most suitable agent * **Sequence**: Agents execute in a predefined order where each agent's output feeds the next * **Manager**: A manager agent dynamically analyzes tasks, determines the optimal agent sequence, handles data passing, and monitors execution. In sequence-based teams, you choose a memory strategy that controls how information passes between agents: * **Summarized Memory Handoff**: Condensed version of relevant information * **Complete Memory Transfer**: Full context and memory transferred to next agent * **Initial Task Context Only**: Only the original task description is passed *** ## Threads Every conversation with an agent gets a unique thread ID that maintains context across multiple messages. Threads record user messages, agent responses, tool calls with request/response payloads, token usage, and execution duration. You can use `thread_id` programmatically to continue conversations across API calls. In the Monitor tab, the **Threads** view lets you inspect any conversation in detail. Click a thread to see the full reasoning chain: every user message, agent response, and tool call with expandable request/response payloads. Each thread also includes an AI Insights panel that scores goal achievement, helping you evaluate how well the agent handled the conversation. Monitor Threads tab showing conversation logs with user messages, agent responses, and tool call details *** ## Tasks Every time an agent is invoked, xpander creates a task to track the execution. Tasks move through statuses: queued, running, completed, failed, or cancelled. Each task records the input, result, timing (created, started, finished), and source (API, SDK, webhook, Slack, Telegram). The **Tasks** view in Monitor shows all agent executions across your organization. You can filter by status or date range to track completion rates and debug failed executions. *** ## Metrics The **Metrics** view in Monitor tracks your agent's usage over time with visual graphs: * **Requests**: total agent invocations * **Outbound API calls by AI**: external tool usage * **Input/Output/Total tokens by day**: message volume and cost tracking Use these to understand usage patterns and optimize token spend. Metrics tab showing agent performance graphs for requests, API calls, and token usage *** ## Personal Agents Personal Agents are fully managed AI assistants powered by the OpenClaw runtime. IT deploys once, and all employees get access. They're available in Slack, Teams, and voice. Each employee can get their own agent with personal memory and conversation history, and agents can delegate to specialized agents for specific tasks. OpenClaw Personal Agent page showing the agent configuration, connected tools, and employee access settings *** ## Tools xpander tools catalog showing built-in tools like Web Search, Send Email, and Code Interpreter alongside connector integrations for Slack, GitHub, Google Drive, Jira, and more Tools are pre-built integrations that let agents take actions beyond chat. Agents use tools autonomously: the LLM decides which tools to call, extracts the right parameters from context, executes the tool, and incorporates the result into its response. Every agent comes with three default tools: `think` (a private scratchpad for reasoning), `analyze` (an evaluation checkpoint), and `multi_tool_use.parallel` (run multiple tools simultaneously). ### Built-in Tools These are ready to use immediately with no setup: Send Email, Web Search, Generate Image, Markdown to PDF, Extract Text (OCR), Code Interpreter, Save CSV File, Text to Speech, File Upload, Create Screenshot from URL, and Sleep. ### Connector Tools Connector tools are integrations with external services that you install from the catalog. Available connectors include Slack, GitHub, Google Drive, Notion, Jira, Linear, Snowflake, BigQuery, MongoDB, and 100+ more. *** ## Knowledge Bases Knowledge Bases let you upload documents so agents can give context-aware responses. At query time, agents search a vector database, retrieve relevant chunks, and synthesize answers with citations. This pattern is known as RAG (Retrieval-Augmented Generation): grounding agent responses in your organization's data. *** ## Next Steps Create an agent in 5 minutes Deep dive into agent settings Browse the connector catalog Build multi-step AI pipelines # Chat Widget Source: https://docs.xpander.ai/guides/deploy/chat-widget Share a hosted chat URL or embed a chat widget in your website Your agent is ready, but your team needs a way to reach it without opening the Agent Studio. The Chat Widget gives every agent a hosted URL anyone in your organization can bookmark, plus an embeddable widget you can drop into any page. Once set up, you can: * Share a hosted chat URL with anyone in your organization * Embed the Agent chat as a widget on any website or app * Suggest pre-defined conversation starters to guide first-time users * Control access with platform login or your SSO provider Pre-requisites: * a [**Custom Agent**](/guides/agents/agent-configuration) Chat is not available for Personal Agents. Create a [Custom Agent](/guides/agents/agent-configuration) to use the hosted chat or embed widget. Hosted chat interface showing Xpander branding, message input, and conversation starters ## Share the Chat URL Each agent gets a unique hosted URL that you can share directly - no code or embedding required. In the Agent Studio, click the **gear** icon and go to the **Channels** tab. Find the **Chat** section. Channels tab showing Chat, Slack, Webhook, Task, MCP, and other deployment sections Your chat URL is displayed directly (e.g., `https://peach-centipede.agents.xpander.ai`). Share this link with your users. Channels tab with the Chat section showing the unique hosted chat URL and Conversation starters button Anyone with the link and the right permissions can open the chat, start new threads, upload files, and have full conversations with your agent. ## Embed Chat Widget You can embed the chat interface in any website using an iframe. The embedded version supports the same features as the hosted version: multiple threads, file uploads, and streaming responses. Replace `YOUR_AGENT_ID` with your agent's ID. You can find it in the **Channels** tab under the **SDK** section (it's the same Agent ID shown there). ```html theme={"dark"} ``` The chat interface is responsive and adapts to the container size. Adjust the iframe dimensions and styling to match your site's layout. Users who open the embedded widget still need to authenticate. If your site handles identity through an SSO provider Xpander supports, connect it so users aren't prompted to log in again. ## Control Access Set who can reach the chat using the [Agent Studio](https://chat.xpander.ai/agents/) > Configuration > General tab > **Access** setting. Access dropdown showing Only me and All users in my account options | Setting | Who can access | | --------------------------- | ------------------------------------------------ | | **Only me** | Only you - useful during development and testing | | **All users in my account** | Anyone in your Xpander organization | ### Authentication Users authenticate through one of two paths: * **Platform login** - Xpander's built-in user management (registration, password recovery, session handling, user profiles). The default, and the right choice for most deployments. * **SSO** - If your organization already uses Okta, Auth0, or Azure AD, connect it so users sign in with their existing credentials. Xpander supports SAML 2.0 and OAuth 2.0 with role mapping and automatic provisioning. SSO is configured in Admin Settings. [Contact sales](https://cal.com/team/xpander-ai/activate) to enable SSO on your workspace. ## Custom Domain Enterprise workspaces can serve the chat from a branded domain like `chat.your-company.com` instead of the default `chat.xpander.ai`. This preserves every chat feature (threads, conversation starters, authentication, and embedding) while keeping the URL on your own domain. [Contact sales](https://cal.com/team/xpander-ai/activate) to set this up. ## Add Conversation Starters Conversation starters are prompt suggestions that appear when a user first opens the chat. They reduce the blank-page problem and help users understand what the agent can do. In the **Chat** section of the Channels tab, click Conversation starters. Click + Add conversation starter to create suggestions. Each starter is a short phrase like "What can you do?" or "Summarize today's tickets." Conversation starters editor with example prompts and Save button Click Save. The starters appear immediately in the chat interface. ## Next Steps Expose your agent to Claude Desktop, Cursor, and other MCP clients Deploy to Slack workspaces Trace execution, debug failures, and review AI performance # MCP Protocol Source: https://docs.xpander.ai/guides/deploy/mcp Expose your agents to Claude Desktop, Cursor, VS Code, and other MCP-compatible clients Your agent has tools, memory, and instructions configured in Xpander, but your developers spend their day in Claude Desktop, Cursor, or VS Code. The MCP server lets those clients call your agent directly, so your team works in the tools they already have. Once set up, you can: * Expose your agent as an MCP server that any compatible client can call * Connect from Claude Desktop, ChatGPT, Cursor, VS Code, or any MCP-compatible client * Let clients kick off agent runs asynchronously and poll for results * Authenticate with a per-server API key without sharing your account credentials Pre-requisites: * a [**Custom Agent**](/guides/agents/agent-configuration) MCP is not available for Personal Agents. Personal Agents only expose API, Slack, Telegram, and Webhook channels. Create a [Custom Agent](/guides/agents/agent-configuration) to use MCP. ## Enable MCP in the Agent Studio In the Agent Studio, click the **gear** icon and go to the **Channels** tab. Find the **MCP** section and toggle it on. Channels tab showing API, SDK, Chat, Slack, Webhook, Task, and MCP sections Click Details. The modal shows your **MCP server URL**, **API key**, and **transport** options (HTTP or SSE). Under **Easy setup**, select your client - **Cursor**, **Claude**, **Windsurf**, or **Raw JSON** - and copy the ready-to-paste configuration. MCP details modal showing server URL, API key, transport selection, and easy setup configs for Cursor, Claude, Windsurf Click Publish to make the MCP server live. ## Connect from a Client The Agent Studio's **Easy setup** generates the exact command for your client. The page also gives you a **Raw JSON** option you can paste into any MCP-compatible client's config file. The MCP server supports two transports: | Transport | URL shape | | ------------------ | --------------------------------------------- | | **HTTP** (default) | `https://mcp.xpander.ai/ag_YOUR_AGENT_ID/` | | **SSE** | `https://mcp.xpander.ai/ag_YOUR_AGENT_ID/sse` | HTTP is the standard choice and works with all current MCP clients. SSE (Server-Sent Events) enables server-initiated updates during long-running tasks. ### Easy setup (Cursor, Claude Desktop, Windsurf) The Agent Studio generates an `npx install-mcp` command per client that registers the server and writes the config for you. ```bash theme={"dark"} npx install-mcp \ --name "" \ --client cursor \ --header "x-api-key:" \ -y --oauth no ``` Fill in the placeholders: | Placeholder | What to use | | ----------- | -------------------------------------------------------------------------------------------------------------------------------------- | | `` | The per-agent MCP URL from the **Details** modal, e.g. `https://mcp.xpander.ai/ag_YOUR_AGENT_ID/` (or append `/sse` for SSE transport) | | `` | A short, slug-friendly label for the server in your client's MCP list (lowercase letters, numbers, hyphens) - e.g. `support-bot` | | `` | The Xpander API key from the **Details** modal | Swap `--client cursor` for `--client claude` or `--client windsurf` to install in those apps. Run the command once per client. ### Raw JSON For any other MCP-compatible client, paste this into its config file (e.g., `~/Library/Application Support/Claude/claude_desktop_config.json` for Claude Desktop on macOS): ```json theme={"dark"} { "your_agent_name": { "command": "npx", "args": [ "mcp-remote", "https://mcp.xpander.ai/ag_YOUR_AGENT_ID/", "--header", "Authorization:${AUTH_TOKEN}" ], "env": { "AUTH_TOKEN": "Bearer YOUR_API_KEY" } } } ``` For SSE, append `/sse` to the URL: ```json theme={"dark"} "https://mcp.xpander.ai/ag_YOUR_AGENT_ID/sse" ``` Restart your client after saving the config. ## Use the Available Tools Each agent's MCP server exposes two tools. The flow is asynchronous because agent runs can take seconds to minutes (tool calls, multi-step reasoning, external API requests). Call `invoke_agent` to start a task, then poll `get_task_status` until it completes. | Tool | What it does | | ----------------- | ------------------------------------------------------------------------------------------------------------------- | | `invoke_agent` | Fire-and-forget. Creates an asynchronous agent task with the given prompt and returns the task details immediately. | | `get_task_status` | Checks the current state of a task created with `invoke_agent` and returns its result once complete. | ### invoke\_agent | Parameter | Required | Description | | --------- | -------- | --------------------------------------------------------- | | `prompt` | Yes | Natural language prompt/instruction to send to the agent. | Returns a `result` field containing the task details, including the task ID you'll pass to `get_task_status`. ### get\_task\_status | Parameter | Required | Description | | --------- | -------- | -------------------------------------------------------- | | `task_id` | Yes | The unique task identifier returned from `invoke_agent`. | Returns a `result` field with the current task state and, once complete, the agent's response. ### Example queries * "Ask my agent to summarize the latest support tickets" → `invoke_agent` * "Check on the task you just kicked off" → `get_task_status` ## Authentication Each MCP server is protected by a per-agent API key generated in the Agent Studio. The client passes it on every request, either as an `x-api-key` header (when using `npx install-mcp`) or as an `Authorization: Bearer ` header (Raw JSON). There's no interactive OAuth flow. The key is set up once when you install the server and reused on every call. The API key is stored in the client's MCP config file (e.g., `claude_desktop_config.json`). Treat that file as a secret: don't commit it or share it after the install. ## Security * **Per-agent API key** - Each MCP server has its own key, scoped to a single agent. No shared account credentials sit in the config. * **Scoped access** - The key only authorizes calls to that agent's MCP tools (`invoke_agent` and `get_task_status`); it can't access other agents or org-level operations. * **Revoke anytime** - Rotate or revoke the key from the Agent Studio's **MCP** section in the Channels tab. ## Troubleshooting * Verify your `claude_desktop_config.json` syntax is valid JSON. * Check the file location: `~/Library/Application Support/Claude/claude_desktop_config.json` (macOS). * Restart Claude Desktop completely. * Check Claude logs: `~/Library/Logs/Claude/mcp.log`. * Confirm the API key in your MCP config matches the one in the Agent Studio's MCP **Details** modal. * If you rotated the key, re-run `install-mcp` or update the Raw JSON config so the client picks up the new key. * Check organization permissions - some agents may be restricted to specific users. * Verify the agent is published in the Agent Studio. * Ensure the agent isn't stopped or in an error state. * Check the agent's logs in the Monitor tab. ## Next Steps Trigger agents from external systems Run agents on a schedule Trace execution, debug failures, and review AI performance # Omni MCP Server Source: https://docs.xpander.ai/guides/deploy/omni-mcp Chat with your Omni agent and operate the platform from Claude, ChatGPT, and other MCP clients Omni is your personal Xpander router agent: it can answer directly, task your other agents, build and edit agents, manage schedules, and search your organization's knowledge. The Omni MCP server puts all of that behind a single endpoint you connect to Claude, ChatGPT, Cursor, or any MCP-compatible client, so you work with Omni without leaving the tool you're already in. ``` https://omni.xpander.ai/mcp ``` Once connected, you can: * Chat with Omni straight from your MCP client, and keep the conversation going across turns * Kick off long-running work asynchronously and poll for the result * Ask Omni to task your other agents, build or edit agents, and search your organization's knowledge - all through the conversation * Authenticate once with OAuth 2.1 - you sign in with your Xpander credentials, and every call runs with your permissions This is a different endpoint from the [per-agent MCP server](/guides/deploy/mcp) (`mcp.xpander.ai/ag_...`), which exposes one specific agent. The Omni MCP server is scoped to **you**: your OAuth sign-in resolves your personal Omni agent and applies your access. ## Tools | Tool | What it does | | ---------------- | ---------------------------------------------------------------------------------------------------------- | | `ask_omni` | Send Omni a message and wait for its answer. Returns Omni's Markdown reply plus a `conversation_id`. | | `ask_omni_async` | Send Omni a message without waiting. Returns the `conversation_id` immediately; poll with `get_omni_task`. | | `get_omni_task` | Check the status and result of a conversation started with `ask_omni` / `ask_omni_async`. | These three tools are deliberately the whole surface: everything else - discovering agents, building them, managing tasks, searching knowledge - happens by asking Omni for it in the conversation. Omni acts with your permissions, so which agents and data a request can touch is always bounded by your own access. If you want a raw tool surface for one specific agent instead, use the [per-agent MCP server](/guides/deploy/mcp). ### Multi-turn conversations Every answer includes a `conversation_id`. Pass it back into `ask_omni` (or `ask_omni_async`) to continue the same conversation - Omni keeps the full thread, exactly like a chat. ```text theme={"dark"} You: ask_omni("What did the support agent handle this week?") Omni: Conversation ID: task_abc123 This week the support agent closed 42 tickets... You: ask_omni("Draft a summary email to the team", conversation_id="task_abc123") Omni: Conversation ID: task_abc123 Here's a draft: ... ``` ### Long-running work Omni runs can take from seconds to minutes (tool calls, multi-step reasoning, tasking other agents). For work that might exceed your client's tool-call timeout, start it with `ask_omni_async` and poll `get_omni_task` with the returned `conversation_id` until it's done. ## Authentication The Omni MCP server authenticates with **OAuth 2.1 only** - there are no API keys to copy into config files. Clients that support remote MCP OAuth (ChatGPT custom connectors, Claude via `mcp-remote`, Cursor, and most modern MCP clients) discover the flow automatically from the server URL. You sign in once in the browser with your Xpander credentials, the client stores the token, and every call runs as you. Because the sign-in is personal, the connection is too: Omni resolves to **your** Omni agent, sees your conversations, and acts with your access - nothing to configure. ## Connect from a client Edit `~/Library/Application Support/Claude/claude_desktop_config.json` (macOS) and add the Omni server. With OAuth, `mcp-remote` runs the sign-in flow the first time you start Claude: ```json theme={"dark"} { "mcpServers": { "xpander-omni": { "command": "npx", "args": [ "-y", "mcp-remote@latest", "https://omni.xpander.ai/mcp" ] } } } ``` Restart Claude Desktop after saving; `mcp-remote` opens the browser sign-in the first time. Then ask: *"Ask Omni what my agents did today."* In ChatGPT, add a custom connector pointing at `https://omni.xpander.ai/mcp`. ChatGPT runs the OAuth flow; sign in with your Xpander credentials to authorize it. Once connected, the `ask_omni` tools appear in the connector's tool list. Add the server to your client's MCP config with the URL `https://omni.xpander.ai/mcp`. The client discovers the OAuth flow from the URL and opens the sign-in on first use. ## How Omni responds over MCP Runs that arrive through the MCP server are marked as MCP-sourced, and Omni adapts to the channel: because MCP clients render plain Markdown (no interactive Xpander cards), Omni answers in clean, self-contained Markdown and never raises a card that would stall the run. If a task needs something it can't get non-interactively - a missing secret, or a connector that needs authorization - Omni does as much as it can and tells you in its reply what's missing and how to resolve it in the Xpander app. In the Xpander app, these conversations show up in your task list tagged with their origin - for example "MCP - ChatGPT" or "MCP - Claude" - so you can always tell which client a run came from. If Omni needs you to authorize a connector mid-run, `ask_omni` returns the authorization link right away along with the `conversation_id`. Complete the authorization, then fetch the result with `get_omni_task` - the run resumes on its own. ## Troubleshooting The server is OAuth-only - an `x-api-key` header (or any static key) is not accepted. Remove any key-based config, re-add the connector, and complete the browser sign-in with your Xpander credentials. * Make sure the connector URL is exactly `https://omni.xpander.ai/mcp`. * Complete the sign-in in the browser window the client opens; some clients cache a stale token - remove and re-add the connector to restart the flow. Open the link from Omni's reply, complete the authorization in the Xpander app, then call `get_omni_task` with the same `conversation_id` to get the finished result. ## Next steps Expose a single Custom Agent as its own MCP server Learn what Omni can do across the platform # Scheduled Tasks Source: https://docs.xpander.ai/guides/deploy/scheduled-tasks Run your agents automatically on a cron schedule Scheduled tasks let you run an agent at recurring intervals (every few minutes, daily, weekly, or on any custom cadence) without anyone needing to trigger it manually. Useful for automated reports, periodic data syncs, monitoring jobs, or any recurring agent workflow. Once set up, you can: * Run an agent on a quick preset (every N minutes/hours, daily, weekly) or a custom cron expression * Pass fixed instructions to the agent at each run, like a stored prompt * Run the task as a specific user so per-user memory, permissions, and credentials apply * Monitor every scheduled execution from the Tasks view alongside manual runs Pre-requisites: * a [**Custom Agent**](/guides/agents/agent-configuration) Scheduled tasks are not available for Personal Agents. Personal Agents only expose API, Slack, Telegram, and Webhook channels. Create a [Custom Agent](/guides/agents/agent-configuration) to schedule recurring runs. ## Create a Scheduled Task In the Agent Studio, click the **gear** icon and go to the **Channels** tab. Find the **Task** section. Task section in Channels tab showing Add Task button Click Add Task to open the task configuration panel. Task configuration showing instructions, schedule presets, interval settings, and user context In the **Instructions** field, describe what the agent should do on each run. For example: "Check for open P0 incidents and post a summary to #ops-alerts." Choose a **Quick Preset** (every 5 minutes, hourly, daily, etc.) or configure a **Custom Schedule** with a specific interval, time, and active days. The current cron expression is shown at the bottom of the scheduler. Click Publish. The agent will run automatically at the configured times. All schedule times are in UTC. Convert from your local timezone accordingly. For example, 9:00 AM US Eastern is 13:00 or 14:00 UTC depending on daylight saving time. ## Configure the Schedule ### Use Quick Presets Select a preset from the dropdown for common intervals like every 5 minutes, every hour, or once daily. ### Build a Custom Schedule Switch to **Custom Schedule** for more control: * **Interval** vs **Specific Time** - run every N minutes/hours, or at a fixed time each day * **On days** - select which days of the week the task should run (all days are selected by default) The panel shows the resolved cron expression so you can verify the schedule. ### Write Cron Expressions Under the hood, schedules use standard five-field cron syntax: ``` ┌───────── minute (0–59) │ ┌─────── hour (0–23) │ │ ┌───── day of month (1–31) │ │ │ ┌─── month (1–12) │ │ │ │ ┌─ day of week (0–6, Sunday = 0) │ │ │ │ │ * * * * * ``` | Schedule | Expression | | ------------------------ | -------------- | | Every hour | `0 * * * *` | | Every day at 9 AM UTC | `0 9 * * *` | | Every Monday at 8 AM UTC | `0 8 * * 1` | | Every 15 minutes | `*/15 * * * *` | | First of every month | `0 0 1 * *` | ### Try It: Cron Builder Edit each field, see the expression update, and get a plain-English description of when your schedule will fire.