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

# A2A Protocol

> Agent-to-agent task exchange and discovery for AI agents, backed by did:web identity and public Agent Cards.

# A2A Protocol

Every Anima agent gets a `did:web` DID and a public Agent Card, so other agents -- Anima-hosted or not -- can discover it and learn what it can do. On top of that identity layer, Anima gives each agent a task queue: a structured way to hand a job to one of your agents, tag who it's from, and track it from submission through completion.

## How A2A Works

1. **Identity** -- every agent has a `did:web` DID and a DID document (containing its public key) published at a world-readable URL
2. **Discovery** -- fetch any agent's Agent Card (`/.well-known/agent.json`) to see its capabilities, DID, and contact info
3. **Task submission** -- submit a structured task onto one of your own agents' task queues (first-party), tagged with a sender DID
4. **Dispatch** -- send a *signed* task to another agent by DID; Anima signs it with your agent's key and the recipient verifies that signature against your published DID document before accepting it
5. **Tracking** -- poll for status (`submitted` -> `working` -> `completed` / `failed` / `input_required`), or cancel a task that hasn't finished yet

<Note>
  Task submission (`submitTask`, `getTask`, `listTasks`, `cancelTask`) is scoped to your own org -- the `agentId` in every task endpoint must be an agent your org owns. `discover` is unscoped: it's a plain, unauthenticated fetch of the target's public Agent Card, on Anima or anywhere else.
</Note>

## Discovering an Agent

Fetch an agent's Agent Card directly from its `/.well-known/agent.json` URL. This works for any agent that publishes one -- it doesn't go through the Anima API and doesn't require an API key.

<Tabs items={["Node.js", "Python", "CLI"]}>
  <Tab value="Node.js">
    ```ts theme={null}
    import { Anima } from "@anima-labs/sdk";

    const anima = new Anima({ apiKey: "ak_..." });

    const card = await anima.a2a.discover("https://sender.useanima.sh");
    console.log(card.name, card.did, card.capabilities);
    ```
  </Tab>

  <Tab value="Python">
    ```python theme={null}
    from anima import Anima

    anima = Anima(api_key="ak_...")

    card = anima.a2a.discover("https://sender.useanima.sh")
    print(card["name"], card["did"], card["capabilities"])
    ```
  </Tab>

  <Tab value="CLI">
    ```bash theme={null}
    anima a2a discover https://sender.useanima.sh
    ```
  </Tab>
</Tabs>

## Submitting a Task

Submit a task to one of your agents. `agentId` is the receiving agent (must belong to your org); `from` is a sender DID you supply -- it's recorded on the task but not cryptographically verified.

<Tabs items={["Node.js", "Python", "Go", "CLI"]}>
  <Tab value="Node.js">
    ```ts theme={null}
    const task = await anima.a2a.submitTask("ag_receiver456", {
      type: "purchase-order",
      input: {
        vendor: "Office Supplies Inc",
        items: [
          { name: "Printer paper", quantity: 10, unitPrice: 8.99 },
          { name: "Ink cartridges", quantity: 4, unitPrice: 24.99 },
        ],
        budget: 200,
      },
      fromDid: "did:web:agents.useanima.sh:org_abc123:ag_sender123",
    });

    console.log(`Task ID: ${task.id}`);
    console.log(`Status: ${task.status}`); // "submitted"
    ```
  </Tab>

  <Tab value="Python">
    ```python theme={null}
    task = anima.a2a.submit_task(
        "ag_receiver456",
        type="purchase-order",
        input={
            "vendor": "Office Supplies Inc",
            "items": [
                {"name": "Printer paper", "quantity": 10, "unitPrice": 8.99},
                {"name": "Ink cartridges", "quantity": 4, "unitPrice": 24.99},
            ],
            "budget": 200,
        },
        from_did="did:web:agents.useanima.sh:org_abc123:ag_sender123",
    )

    print(f"Task ID: {task.id}")
    print(f"Status: {task.status}")
    ```
  </Tab>

  <Tab value="Go">
    ```go theme={null}
    import "github.com/anima-labs-ai/go"

    client := anima.NewClient("ak_...")

    task, err := client.A2A.SubmitTask(ctx, "ag_receiver456", anima.SubmitA2ATaskParams{
        Input: map[string]any{
            "vendor": "Office Supplies Inc",
            "items": []map[string]any{
                {"name": "Printer paper", "quantity": 10, "unitPrice": 8.99},
            },
            "budget": 200,
        },
    })
    ```
  </Tab>

  <Tab value="CLI">
    ```bash theme={null}
    anima a2a send \
      --agent ag_receiver456 \
      --type purchase-order \
      --input '{"vendor":"Office Supplies Inc","budget":200}' \
      --from-did did:web:agents.useanima.sh:org_abc123:ag_sender123
    ```
  </Tab>
</Tabs>

## Dispatching a Task to Another Agent

`dispatch` is the authenticated agent-to-agent path. Anima signs the task with your sending agent's key and delivers it to the recipient's public inbound endpoint, which verifies the signature against your published DID document before accepting it. Unlike `submitTask` -- where `from` is an unverified label on your own queue -- a dispatched task's sender identity is cryptographically proven.

The recipient is addressed by DID. Your sending agent must be registered in the [Agent Registry](/registry/overview), and signing happens server-side -- your private key never leaves Anima.

<Tabs items={["Node.js", "Python", "Go", "CLI"]}>
  <Tab value="Node.js">
    ```ts theme={null}
    const task = await anima.a2a.dispatch("ag_sender123", {
      toDid: "did:web:agents.useanima.sh:org_xyz:ag_receiver456",
      type: "purchase-order",
      input: { vendor: "Office Supplies Inc", budget: 200 },
    });

    console.log(`Dispatched: ${task.id} (${task.status})`);
    ```
  </Tab>

  <Tab value="Python">
    ```python theme={null}
    task = anima.a2a.dispatch(
        "ag_sender123",
        to_did="did:web:agents.useanima.sh:org_xyz:ag_receiver456",
        type="purchase-order",
        input={"vendor": "Office Supplies Inc", "budget": 200},
    )
    ```
  </Tab>

  <Tab value="Go">
    ```go theme={null}
    task, err := client.A2A.Dispatch(ctx, "ag_sender123", anima.DispatchA2ATaskParams{
        ToDID: "did:web:agents.useanima.sh:org_xyz:ag_receiver456",
        Type:  "purchase-order",
        Input: map[string]any{"vendor": "Office Supplies Inc", "budget": 200},
    })
    ```
  </Tab>

  <Tab value="CLI">
    ```bash theme={null}
    anima a2a dispatch \
      --from ag_sender123 \
      --to-did did:web:agents.useanima.sh:org_xyz:ag_receiver456 \
      --type purchase-order \
      --input '{"vendor":"Office Supplies Inc","budget":200}'
    ```
  </Tab>
</Tabs>

<Note>
  You never call the inbound endpoint (`POST /v1/a2a/inbound`) directly -- it's the public, signature-authenticated surface where *dispatched* tasks arrive. It takes no API key: the request is authenticated purely by the sender's DID signature (verified against the sender's DID document), then the task is recorded on the receiving agent, in the receiver's org. Resolving non-Anima `did:web` senders is off by default (see [Configuration](#configuration)).
</Note>

## Tracking a Task

<Tabs items={["Node.js", "Python", "Go", "CLI"]}>
  <Tab value="Node.js">
    ```ts theme={null}
    // Get a single task
    const task = await anima.a2a.getTask("ag_receiver456", "task_abc123");

    // List tasks, optionally filtered by status
    const { items, nextCursor } = await anima.a2a.listTasks("ag_receiver456", {
      status: "working",
      limit: 20,
    });

    // Cancel a submitted or working task
    await anima.a2a.cancelTask("ag_receiver456", "task_abc123");
    ```
  </Tab>

  <Tab value="Python">
    ```python theme={null}
    task = anima.a2a.get_task("ag_receiver456", "task_abc123")

    result = anima.a2a.list_tasks("ag_receiver456", status="working", limit=20)

    anima.a2a.cancel_task("ag_receiver456", "task_abc123")
    ```
  </Tab>

  <Tab value="Go">
    ```go theme={null}
    task, err := client.A2A.GetTask(ctx, "ag_receiver456", "task_abc123")

    page, err := client.A2A.ListTasks(ctx, "ag_receiver456", &anima.A2ATaskListParams{
        Status: anima.A2ATaskStatusCompleted,
    })

    task, err = client.A2A.CancelTask(ctx, "ag_receiver456", "task_abc123")
    ```
  </Tab>

  <Tab value="CLI">
    ```bash theme={null}
    anima a2a tasks --agent ag_receiver456 --status working --limit 20
    ```
  </Tab>
</Tabs>

## Task Lifecycle

| Status | Description |
| - | - |
| `submitted` | Task created, not yet picked up |
| `working` | Task is being processed |
| `input_required` | Processing is paused, waiting on additional input |
| `completed` | Task finished successfully |
| `failed` | Task errored |
| `canceled` | Task was canceled (only reachable from `submitted`/`working`) |

## API Reference

| Endpoint | Method | Description |
| - | - | - |
| `/v1/agents/{fromAgentId}/a2a/dispatch` | POST | Dispatch a signed task to another agent by DID |
| `/v1/agents/{agentId}/a2a/tasks` | POST | Submit a task to an agent |
| `/v1/agents/{agentId}/a2a/tasks` | GET | List an agent's tasks |
| `/v1/agents/{agentId}/a2a/tasks/{taskId}` | GET | Get task status and result |
| `/v1/agents/{agentId}/a2a/tasks/{taskId}/cancel` | POST | Cancel a submitted or working task |

Base URL: `https://api.useanima.sh/v1`. All endpoints above require `Authorization: Bearer ak_...` (or another valid key) for an org that owns `agentId`.

Discovery and signed inbound are separate surfaces that take no API key:

| Endpoint | Method | Description |
| - | - | - |
| `https://<agent-host>/.well-known/agent.json` | GET | Fetch an agent's public Agent Card |
| `https://agents.useanima.sh/{orgId}/{agentId}/did.json` | GET | Resolve an agent's `did:web` DID document |
| `/v1/a2a/inbound` | POST | Receive a DID-signed task from another agent (authenticated by signature, not an API key) |

## Configuration

Inbound A2A behavior is controlled by these environment variables:

| Variable | Default | Description |
| - | - | - |
| `ANIMA_A2A_REQUIRE_DID_AUTH` | `true` | Require a valid DID signature on inbound tasks (set `false` to disable the inbound endpoint) |
| `ANIMA_A2A_MAX_SKEW` | `300` | Maximum timestamp skew, in seconds, for a signed inbound request |
| `ANIMA_A2A_ALLOW_EXTERNAL_DID` | `false` | Resolve non-Anima `did:web` senders (off by default; Anima-to-Anima works regardless) |
| `ANIMA_A2A_INBOUND_RATE` | `30` | Maximum inbound requests per source IP per minute |

## CLI

```bash theme={null}
# Discover an agent's capabilities
anima a2a discover <url>

# Submit a task to one of your own agents
anima a2a send --agent <id> --type <type> --input <json> [--from-did <did>]

# Dispatch a signed task to another agent by DID
anima a2a dispatch --from <id> --to-did <did> --type <type> --input <json>

# List tasks for an agent
anima a2a tasks --agent <id> [--status <status>] [--cursor <cursor>] [--limit <n>]
```

A2A pairs with the [Agent Registry](/registry/overview) and agent identity commands:

```bash theme={null}
# Registry: publish and discover agents
anima registry register --agent-id <id> --name <name> [--description <desc>] [--tags <tags>] [--public]
anima registry search [--query <text>] [--capability <cap>] [--trust-min <0-100>] [--tags <tags>]
anima registry lookup --did <did>

# Identity: inspect an agent's DID document and Agent Card
anima identity did --agent <id>
anima identity card --agent <id>
```

## Next Steps

* [Agent Cards](/identity/agent-cards) -- Agent Card format and publishing
* [DID Method](/identity/did-method) -- `did:web` DID documents and resolution
* [Agent Registry](/registry/overview) -- Publish and search for agents


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.