> ## Documentation Index
> Fetch the complete documentation index at: https://docs.xpander.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# 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.

<Info>
  When the same parameter appears in multiple places, query parameters take priority over body parameters, which take priority over defaults.
</Info>

### 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&params_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.  |

<Warning>
  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.
</Warning>

## 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.

<Note>
  MCP is not available for Personal Agents. Create a [Custom Agent](/guides/agents/agent-configuration) to use MCP.
</Note>

### 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 <URL> \
  --name "<NAME>" \
  --client cursor \
  --header "x-api-key:<API_KEY>" \
  -y --oauth no
```

| Placeholder | What to use                                                                     |
| ----------- | ------------------------------------------------------------------------------- |
| `<URL>`     | The per-agent MCP URL from the Details modal (append `/sse` for SSE transport). |
| `<NAME>`    | A short slug for the server in your client's MCP list, e.g. `support-bot`.      |
| `<API_KEY>` | 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 <key>` (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.

<Warning>
  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.
</Warning>

### Troubleshooting

<AccordionGroup>
  <Accordion title="MCP server not showing in Claude Desktop">
    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`.
  </Accordion>

  <Accordion title="Authentication fails">
    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.
  </Accordion>

  <Accordion title="Agent invocation fails">
    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.
  </Accordion>
</AccordionGroup>

## 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

<CardGroup cols={2}>
  <Card title="REST API reference" icon="globe" href="/api-reference/v1/agents/invoke-sync">
    Sync, async, and stream endpoints.
  </Card>

  <Card title="MCP guide" icon="bridge" href="/guides/deploy/mcp">
    Full MCP setup walkthrough with screenshots.
  </Card>

  <Card title="Webhooks guide" icon="webhook" href="/guides/deploy/webhooks">
    Full webhook reference with the Workbench tester.
  </Card>

  <Card title="Scheduled tasks" icon="clock" href="/guides/deploy/scheduled-tasks">
    Cron-driven invocations.
  </Card>
</CardGroup>
