@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 Xpander Chat under the agent’s settings, Channel > Configure.
REST API
The default channel for programs. Turn on Developer access in the agent’s Channel settings to reach it over REST, the SDK and webhooks; the row shows the agent’s API endpoint,https://api.<host>/v1/agents/<id> (api.xpander.ai on xpander cloud), and links to Open API keys:
Full endpoint reference: REST API → Agents.
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 work out of the box.
Set up in Xpander Chat under the agent’s Channel settings. Each Slack workspace is one connected account; Xpander Chat walks through OAuth.
Channel progress preferences
Slack, Teams and Telegram use a status line by default. Channel bindings accept nullableverbose_task_progress (NULL inherits the bot preference); bot settings accept the same key. Explicit verbose opt-in wins over the legacy stream_task_progress: false setting. Clients should write the new preference and preserve existing legacy values. This affects channel presentation only; REST invocation SSE events remain unchanged.
Webhooks
Enable
In Xpander Chat, open the agent’s Channel settings and turn on Developer access. Public webhook URL mints a URL that is itself the credential, so a caller needs no API key; Regenerate URL revokes the old one. The requests below use the key-based endpoint, which takes an API key on every call.Make requests
All webhook requests are POST tohttps://webhook.xpander.ai/:
Optional parameters:
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.asynchronous=true to return immediately. Best for long-running tasks, file processing, or when you don’t need the result inline.
{"status": "Started", "task_id": "..."} immediately. Use the task_id to find the task and its result in Xpander Chat.
Upload files
Upload files usingmultipart/form-data. The agent automatically processes them: OCR for images, text extraction for PDFs, transcription for audio.
Extract data from responses
Usegetter with dot notation to extract a specific field from the agent’s response instead of the full object:
"Q4 revenue increased 15%".
Behind a load balancer with an idle timeout, an AWS ALB answers 504 after 60 seconds by default, a synchronous call or a key-based webhook whose turn runs longer never returns. Use the asynchronous form and poll the task for turns that may take more than a minute.
Map dynamic parameters
Useparams_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:
task_id, user_id, user_email, user_first_name, user_last_name, prompt. A task_id belongs to the agent that first used it. Reusing it continues that thread. Sending it to another agent answers 409 on a synchronous call. On an asynchronous call, the message does not run.
Pass MCP OAuth tokens
If your agent uses skills served over MCP with OAuth authentication, pass pre-authenticated user tokens viauser_tokens to bypass the interactive OAuth flow during webhook execution:
graph.items for entries with type: "mcp".
Error codes
An agent whose status is
INACTIVE does not run, and no task is recorded. A synchronous call answers 423 with AgentInactive and The agent '<name>' is currently inactive and cannot be invoked. An asynchronous call still answers {"status": "Started", "task_id": ...}, but nothing runs and that task never exists. Check the agent’s status before you rely on an asynchronous webhook.
MCP (Model Context Protocol)
Agents are reached over MCP through two endpoints, neither of which is configured per agent in Xpander Chat:- The API’s MCP endpoint,
https://api.xpander.ai/mcp/, is the xpander API over MCP: the same control plane and data plane calls, listing and invoking agents, reading tasks and threads, reaching skills, custom functions, workspace files and schedules. It is not an agent. It signs in with OAuth 2.1; an API key is not accepted. Client setup is on Model Context Protocol. - The Omni endpoint,
https://omni.xpander.ai/mcp, is Omni, the built-in agent, behind one address. Through it a client does everything you can do in Xpander Chat: find and task your organization’s agents, assemble skills and agents, start cloud sessions, ask what a run did. It signs in with OAuth in the browser. See Omni in your MCP client.
/mcp. It comes from global.apiPublicUrl, or from the API host (global.hosts.api or api.<global.domain>) when that value is not set. A host set only on the API’s own ingress does not count. If the values give neither, the page says the gateway is not available yet. On a Hybrid install the chart has no value to set: it serves mcp.<your domain> from its ingress. If the page says the gateway is not available, contact xpander support.
While an agent works with a skill served over MCP:
- Elicitation. When the server asks for input, the person answers the prompt in the chat.
- MCP Tasks. Long-running MCP operations run in the background and return their result when done.
- Status. A skill shows Connected only after a real call worked; a dropped MCP session reconnects.
Scheduled tasks (cron)
A cron expression that creates a task on a schedule. The task input is whatever you configure in Xpander Chat: a fixed prompt or a templated one with placeholders. The agent’s@on_task handler runs as if a user invoked it.
While the agent’s status is INACTIVE, its schedules are skipped: no task, no entry in the run history. The schedule itself is kept and fires again once the agent is ACTIVE.
Agent-to-agent (A2A)
Who can send tasks
Each agent chooses which other agents may send it tasks: agent settings > Channel > Configure > Who can send tasks. The Omni switch decides whether Omni can find this agent and send it a teammate’s task when it matches the agent’s skills. For other agents, pick Any agent, Selected agents or No agents. Each task shows which rule allowed it. In chat, an@Agent mention sends that agent a task.
Delegate from one agent to another
Inside your organization, a manager agent delegates to a specialist agent by calling it as a skill, within the Who can send tasks rule above.Call an agent from code
From a parent agent’s handler, calling a child agent looks like calling any other skill. The child appears inagent.tools.list once it’s been added as a dependency in Xpander Chat:
Picking a channel
A common combination:- 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.
- Agent-to-agent for delegation from a manager agent to a specialist.
@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
REST API reference
Sync, async, and stream endpoints.
MCP guide
Full MCP setup walkthrough with screenshots.
Webhooks guide
Full webhook reference with the tester in Xpander Chat.
Scheduled tasks
Cron-driven invocations.

