Interoperability

A2A partner quickstart

AXL serves the A2A protocol (v1.0, JSON-RPC binding) for any agent with [interop] a2a = true. Three curl commands cover discovery through a finished task.

Credentials

Ask the AXL operator for an API key (axl token create --name your-org on their side). Every RPC call carries it as a bearer:

AUTH='Authorization: Bearer axl_key_...'
BASE='https://axl.example.com'      # the deployment's PUBLIC_BASE_URL
AGENT='support'                     # the agent key from the card URL you were given

A JWT from a federated IdP the deployment trusts works the same way.

Discover the card

curl "$BASE/a2a/$AGENT/agent-card.json"

Deployments that set A2A_WELL_KNOWN_AGENT also serve that agent's card at $BASE/.well-known/agent-card.json. The card lists the agent's skills, the JSON-RPC endpoint (supportedInterfaces[0].url), and the accepted security schemes.

Delegate a task

curl -X POST "$BASE/a2a/$AGENT" -H "$AUTH" -H 'Content-Type: application/json' -d '{
  "jsonrpc": "2.0", "id": 1, "method": "SendMessage",
  "params": { "message": {
    "messageId": "m-1", "role": "ROLE_USER",
    "parts": [{ "text": "Summarize the open tickets for ACME." }]
  } }
}'

SendMessage blocks (the spec default) until the task completes, fails, or needs your input - bounded by a server-side wait cap of 120 seconds, after which you get the current TASK_STATE_WORKING task and continue by polling. The completed task carries the answer in status.message and any produced files in artifacts[] (fetch artifact urls with the same bearer). Set "configuration": {"returnImmediately": true} to get the task id back instantly instead of waiting.

Poll (or answer a question)

curl -X POST "$BASE/a2a/$AGENT" -H "$AUTH" -H 'Content-Type: application/json' -d '{
  "jsonrpc": "2.0", "id": 2, "method": "GetTask",
  "params": { "id": "TASK_ID", "historyLength": 20 }
}'

A task in TASK_STATE_INPUT_REQUIRED is asking you something: status.message carries the question as text plus a machine-readable data part. For an elicitation (the agent wants structured input) the data part is {"type": "elicitation", "tool": ..., "ui_component": ..., "payload": {...}} - the payload describes the requested value (for present_choices, the options list). For an approval (the agent wants permission for an action) it is {"type": "approval", "tool": ..., "risk": ..., "description": ..., "answer": {...}}, where answer spells out the expected reply shape. Answer by sending a message bound to the task:

curl -X POST "$BASE/a2a/$AGENT" -H "$AUTH" -H 'Content-Type: application/json' -d '{
  "jsonrpc": "2.0", "id": 3, "method": "SendMessage",
  "params": { "message": {
    "messageId": "m-2", "taskId": "TASK_ID", "role": "ROLE_USER",
    "parts": [{ "data": { "selected": "pro" } }]
  } }
}'

For approval-type questions the data part is {"decision": "approve"} or {"decision": "deny", "reason": "..."} (bare approve / deny text works too).

Notes and limits

  • Multi-turn: reuse the returned contextId in later SendMessage calls to continue the same conversation as new tasks. A terminal task never restarts - a taskId on a terminal task is rejected; send a fresh message with the contextId.
  • While a task is INPUT_REQUIRED, answer via its taskId; a contextId-only message queues behind the parked run.
  • ListTasks (contextId/status filters, pageSize up to 100) and CancelTask ({"id": ...}) round out the v1 surface. totalSize in list responses counts the returned page, not a global total.
  • Files in: send raw bytes ({"raw": "<base64>", "filename": ..., "mediaType": ...}). URL file parts are rejected.
  • Streaming: SendStreamingMessage and SubscribeToTask return SSE where each data: line is a JSON-RPC response. The first frame is always a full Task snapshot; statusUpdate frames follow on state changes (task lifecycle, not token streaming), artifacts arrive as artifactUpdate frames at completion, and the stream closes once the task is terminal or needs your input (reply via SendMessage, then re-subscribe). Push notifications are not supported.
  • RPC responses use content type application/json (streaming: text/event-stream); the agent card is served as application/a2a+json.
  • Conformance: ./scripts/interop/run.sh drives this whole surface (and the MCP server) with the official a2a-sdk and mcp Python clients against a locally booted server - see scripts/interop/README.md.

Next

On this page