# Integrate via A2A Your AI employees speak Google's Agent-to-Agent (A2A) protocol. Any external AI agent that supports A2A can discover your employees, send them tasks, and get results back, without going through the web UI or REST API. ## TL;DR Generate an API key in Settings, Communications. Point your A2A client at `/api/a2a/`. It discovers your employees via the Agent Card, then sends tasks using JSON-RPC 2.0. Responses come back synchronously or via SSE streaming. ## When to Use This Use A2A when your own AI agents need to delegate tasks to your employees. If you are building a multi-agent system where one agent orchestrates others, A2A is the standard protocol for that communication. **A2A vs MCP:** MCP connects agents to tools. A2A connects agents to other agents. Use MCP when your coding tool needs to call an employee. Use A2A when another AI agent needs to send work to an employee. > To connect your employees TO external A2A agents as tools, see Connect A2A Agents in the Tools and Capabilities section. ## How It Works A2A is Google's open protocol for agent-to-agent communication. Your platform exposes each organization's workforce as a single A2A agent, with individual employees listed as "skills" in the Agent Card. - **Agent Card.** Discovery document at `/.well-known/agent.json` lists all active employees - **JSON-RPC 2.0.** Standard protocol. `tasks/send` for synchronous, `tasks/sendSubscribe` for streaming - **Same execution.** A2A messages run through the Dispatcher and execution pipeline, identical to every other channel - **Same billing.** Credits are tracked and charged the same way - **Shared keys.** API keys work across all programmatic channels (REST API, MCP, A2A, Webhooks, Email) ## Enable the Channel The A2A channel is disabled by default. Enable it before connecting: 1. Go to **Settings, Technical, Communications** 2. Find **A2A** under the Inbound channels 3. Toggle it on ## Authentication All requests require a Bearer token in the `Authorization` header. 1. Go to **Settings, Communications** 2. Expand the **Programmatic** group 3. Expand any channel card 4. Create a key (or reuse one from another channel) 5. Include it in every request: ``` Authorization: Bearer sk-your-api-key-here ``` ## Agent Card (Discovery) Fetch the Agent Card to discover available employees: ```bash curl https://api-sistava.com/.well-known/agent.json \ -H "Authorization: Bearer sk-your-api-key" ``` Returns: ```json { "name": "AI Employee Platform", "description": "AI workforce platform with specialized employees", "url": "https://api-sistava.com/api/a2a/", "version": "1.0.0", "capabilities": { "streaming": true, "pushNotifications": false }, "authentication": { "schemes": ["bearer"] }, "defaultInputModes": ["text"], "defaultOutputModes": ["text"], "skills": [ { "id": "employee-uuid-here", "name": "Sarah", "description": "Senior Content Writer", "tags": ["employee"] } ] } ``` Each skill's `id` is the employee UUID you use in task requests. ## Sending Tasks ### Synchronous (tasks/send) Send a task and wait for the complete response: ```bash curl -X POST https://api-sistava.com/api/a2a/ \ -H "Authorization: Bearer sk-your-api-key" \ -H "Content-Type: application/json" \ -d '{ "jsonrpc": "2.0", "id": "1", "method": "tasks/send", "params": { "message": { "role": "user", "parts": [{"type": "text", "text": "Draft a blog post about AI agents"}] }, "metadata": { "employee_id": "EMPLOYEE_UUID_HERE" } } }' ``` Response: ```json { "jsonrpc": "2.0", "id": "1", "result": { "id": "task-uuid", "status": { "state": "completed", "message": { "role": "agent", "parts": [{"type": "text", "text": "Here is the blog post..."}] } }, "artifacts": [ { "parts": [{"type": "text", "text": "Here is the blog post..."}], "index": 0 } ] } } ``` ### Streaming (tasks/sendSubscribe) Same request format but with `tasks/sendSubscribe` as the method. Returns Server-Sent Events (SSE) with status updates as the employee works: ``` data: {"jsonrpc":"2.0","id":"1","result":{"id":"task-1","status":{"state":"submitted"}}} data: {"jsonrpc":"2.0","id":"1","result":{"id":"task-1","status":{"state":"working"}}} data: {"jsonrpc":"2.0","id":"1","result":{"id":"task-1","status":{"state":"completed","message":{"role":"agent","parts":[{"type":"text","text":"Here is the blog post..."}]}}}} ``` ### Python ```python import httpx response = httpx.post( "https://api-sistava.com/api/a2a/", headers={"Authorization": "Bearer sk-your-api-key"}, json={ "jsonrpc": "2.0", "id": "1", "method": "tasks/send", "params": { "message": { "role": "user", "parts": [{"type": "text", "text": "Summarize Q1 revenue trends"}], }, "metadata": {"employee_id": "YOUR_EMPLOYEE_UUID"}, }, }, ) result = response.json()["result"] print(result["status"]["message"]["parts"][0]["text"]) ``` ### JavaScript / Node ```javascript const response = await fetch("https://api-sistava.com/api/a2a/", { method: "POST", headers: { "Authorization": "Bearer sk-your-api-key", "Content-Type": "application/json", }, body: JSON.stringify({ jsonrpc: "2.0", id: "1", method: "tasks/send", params: { message: { role: "user", parts: [{ type: "text", text: "Summarize Q1 revenue trends" }], }, metadata: { employee_id: "YOUR_EMPLOYEE_UUID" }, }, }), }); const { result } = await response.json(); console.log(result.status.message.parts[0].text); ``` ## Task States | State | Meaning | |-------|---------| | `submitted` | Task received, starting execution | | `working` | Employee is processing | | `completed` | Done. Response in `status.message` and `artifacts` | | `failed` | Error occurred. Details in `status.message` | ## Error Responses A2A uses JSON-RPC 2.0 error codes: | Code | Meaning | |------|---------| | -32700 | Parse error (invalid JSON or body too large) | | -32600 | Invalid request (wrong JSON-RPC version or missing method) | | -32601 | Unknown method | | -32602 | Invalid params (missing message, employee_id, or invalid UUID) | | -32001 | Task retrieval not supported (stateless server) | | -32002 | Task cancellation not supported | | -32010 | A2A channel not enabled for this organization | | -32011 | Email not verified | | -32012 | Rate limited | | -32603 | Internal error | ## Supported Methods | Method | Supported | Notes | |--------|-----------|-------| | `tasks/send` | Yes | Synchronous, blocks until response | | `tasks/sendSubscribe` | Yes | SSE streaming with status updates | | `tasks/get` | No | Stateless server, tasks are not stored | | `tasks/cancel` | No | Not supported in this version | ## Rate Limits Same as all programmatic channels: - **Per-IP (failed auth)**: 10 attempts per minute - **Per-API-key**: 120 requests per minute ## Good to Know - **Synchronous by default.** `tasks/send` blocks until the employee responds (up to 5 minutes). Use `tasks/sendSubscribe` for streaming progress updates - **Team leaders.** Send a task to a team leader and they delegate to members. Same behavior as web chat - **Finding employee IDs.** Check the Agent Card (employees are listed as skills), or find UUIDs in the browser URL when viewing an employee - **Managing keys.** Keys are shared across all programmatic channels. Create and manage them from any channel's config panel ## Troubleshooting - **Agent Card returns 401.** Check your Bearer token. The Agent Card endpoint requires authentication. - **"Invalid params" error (-32602).** Make sure `metadata.employee_id` is a valid UUID and `message.parts` contains at least one text part. - **Task stuck in "working" state (streaming).** The employee may be using tools or delegating. With `tasks/sendSubscribe`, you will see status updates. With `tasks/send`, it blocks until done (up to 5 minutes). - **Empty artifacts.** The response content is in `status.message.parts`, not just `artifacts`. Check both fields. ## Frequently Asked Questions **Q: What is the difference between A2A and MCP?** A: MCP connects AI tools to capabilities (tools). A2A connects AI agents to other AI agents. Use MCP when your coding assistant needs to call an employee as a tool. Use A2A when building multi-agent systems where agents delegate work to each other. **Q: Can I use the same API key for A2A and other channels?** A: Yes. API keys are shared across all programmatic channels. **Q: Does the A2A server support push notifications?** A: Not yet. The `capabilities` field in the Agent Card shows `pushNotifications: false`. Use `tasks/sendSubscribe` for streaming updates instead. **Q: Can I retrieve a task result later?** A: No. The server is stateless. Task results are returned inline (synchronous or streaming). If you need to store results, save them on your side. **Q: What text modes are supported?** A: Currently text input and text output only. File and image support are on the roadmap.