A2A
A2A (Agent-to-Agent) is an open standard that lets AI agents work with each other. Put one of your agents on A2A and agents elsewhere, at a partner or in another team’s system, can find out what it does and hand it work. For example, a partner’s purchasing agent can ask your support agent “where is order NW-10428?” and get an answer, without anyone building an integration.
An agent other agents call is an agent in front of someone, so A2A is a channel of the agent, next to its web chat, website widget and messaging channels. There is no separate A2A gateway to create.
Put your agent on A2A
- Open the agent and go to its Channels tab.
- Click Add channel and pick Other agents (A2A).
- Click Publish.
- Under How other agents sign in, make a key for each agent that will call yours. Give each caller its own key, so you can cancel one without affecting the others.
Once published, the channel’s page shows two addresses: the one other agents call, and the Agent Card, a public description of your agent that tells other agents what it can do. Give the other side the Agent Card address and their key; their agent does the rest.
Only an autonomous agent can have this channel, because an A2A caller holds a conversation with it; publishing refuses a workflow agent. Each caller’s key has its own share of the channel’s message limits, and every task runs under the agent’s per-run and spending limits. Unpublish the channel, or switch the agent off, and both addresses stop answering.
For developers
The channel’s page shows both addresses once it is published. Every JSON-RPC call sends a key in the x-api-key header. The endpoint follows this pattern:
https://api.almyty.com/{org}/channels/{channel-id}The Agent Card is generated automatically next to it:
https://api.almyty.com/{org}/channels/{channel-id}/.well-known/agent-card.json.well-known/agent.json is accepted as an alias, and a plain GET on the endpoint
returns the same card. Those three reads are public; the JSON-RPC endpoint is not. The
card and the endpoint answer only while the channel is published and its agent is active:
unpublish the channel, or switch the agent off, and both answer not found.
Connect an agent
Give the calling agent your Agent Card URL and one of the keys. It reads the card, discovers your skills, and starts sending tasks. No manual request building on your side.
https://api.almyty.com/acme/channels/5b1f0c2e-8d4a-4c7e-9a31-2f6d7e8c9b10/.well-known/agent-card.jsonalmyty emits A2A v1.0, so the card carries supportedInterfaces rather than a bare
url; the top-level url is kept alongside it for v0.2.x / v0.3.x clients:
{
"name": "My A2A Agent",
"description": "Answers questions about the pet store.",
"version": "1.0.0",
"supportedInterfaces": [
{
"url": "https://api.almyty.com/acme/channels/5b1f0c2e-8d4a-4c7e-9a31-2f6d7e8c9b10",
"protocolBinding": "JSONRPC",
"protocolVersion": "1.0"
}
],
"capabilities": {
"streaming": true,
"pushNotifications": false,
"extendedAgentCard": true
},
"skills": [
{
"id": "agent-<agent-uuid>",
"name": "My A2A Agent",
"description": "Interact with the My A2A Agent agent",
"tags": [],
"examples": [],
"inputModes": ["text"],
"outputModes": ["text"]
}
],
"defaultInputModes": ["text"],
"defaultOutputModes": ["text"],
"url": "https://api.almyty.com/acme/channels/5b1f0c2e-8d4a-4c7e-9a31-2f6d7e8c9b10"
}Supported methods
Calling agents POST JSON-RPC 2.0 requests to the endpoint. Each method has a v1.0
(PascalCase) name and a v0.2.x / v0.3.x name; both are dispatched to the same handler.
| v1.0 method | v0.x method | Description |
|---|---|---|
SendMessage | message/send | Send a message, get a task back |
StreamMessage | message/stream | Same, streamed back over SSE |
SubscribeToTask | tasks/resubscribe | Reattach an SSE stream to a running task |
GetTask | tasks/get | Get the status and result of a task |
CancelTask | tasks/cancel | Cancel a running task |
ListTasks | tasks/list | List tasks on this endpoint |
GetExtendedAgentCard | agent/getAuthenticatedExtendedCard | The full card, including security schemes |
tasks/send is not a method almyty implements: it returns -32601 Method not found.
Push notification methods (SetTaskPushNotificationConfig and friends) are rejected with
an explicit “not supported” error; use message/stream for real-time updates.
A message carries one or more parts. almyty emits v1.0 parts ({ "text": "..." }) and
accepts all three dialects on input ({ "type": "text", ... }, { "kind": "text", ... },
{ "text": ... }), so a v0.x client does not have to change.
curl -X POST https://api.almyty.com/acme/channels/5b1f0c2e-8d4a-4c7e-9a31-2f6d7e8c9b10 \
-H "x-api-key: your-key" \
-H "Content-Type: application/json" \
-d '{
"jsonrpc": "2.0",
"id": 1,
"method": "message/send",
"params": {
"message": {
"messageId": "msg-1",
"role": "ROLE_USER",
"parts": [{ "text": "List the pets that are available" }]
}
}
}'The response is a JSON-RPC envelope around a Task. message/send returns the Task
directly as result; SendMessage wraps it as result.task.
{
"jsonrpc": "2.0",
"id": 1,
"result": {
"id": "b1f0...-run-uuid",
"contextId": "b1f0...-conversation-uuid",
"status": {
"state": "TASK_STATE_COMPLETED",
"message": {
"messageId": "b1f0...-status",
"role": "ROLE_AGENT",
"parts": [{ "text": "Rosie and Max are available." }],
"taskId": "b1f0...-run-uuid",
"contextId": "b1f0...-conversation-uuid"
},
"timestamp": "2026-01-01T12:00:00.000Z"
},
"history": [],
"artifacts": [
{
"artifactId": "b1f0...-run-uuid-result",
"name": "result",
"parts": [{ "text": "Rosie and Max are available." }]
}
]
}
}Blocking is the default
almyty follows the v1.0 default: a request that sends no configuration, or one that
states neither flag, waits for the task to settle (up to 30 seconds) and returns a
finished Task. To get the task id back immediately and poll with GetTask, say so:
{
"jsonrpc": "2.0",
"id": 1,
"method": "message/send",
"params": {
"message": {
"messageId": "msg-1",
"role": "ROLE_USER",
"parts": [{ "text": "List the pets that are available" }]
},
"configuration": { "returnImmediately": true }
}
}configuration.blocking: false (the v0.x spelling) does the same thing. Stating either
flag always decides; only the unstated case falls through to waiting.
Every call starts an autonomous agent run. Workflow agents are not reachable over A2A: use the agent’s invoke or stream endpoints instead.
Task lifecycle
A2A v1.0 carries the ProtoJSON encoding of the TaskState enum on every binding,
JSON-RPC included, so the states are upper-case TASK_STATE_* strings, not the
kebab-case ones from v0.2.x / v0.3.x.
| State | Description |
|---|---|
TASK_STATE_SUBMITTED | Task received and queued |
TASK_STATE_WORKING | Task is being processed |
TASK_STATE_INPUT_REQUIRED | The agent is waiting on more input |
TASK_STATE_COMPLETED | Task finished successfully |
TASK_STATE_FAILED | Task execution failed, or timed out |
TASK_STATE_CANCELED | Task was canceled |
TASK_STATE_COMPLETED, TASK_STATE_FAILED, TASK_STATE_CANCELED, and
TASK_STATE_REJECTED are terminal: nothing transitions out of them.
The keys on the channel’s page are gateway keys, so Gateway Authentication applies to them: add another sign-in method there, or revoke a key. Discovery endpoints such as the Agent Card stay public so other agents can find you.