Webhook (A2A)

Run an agent from your own code. Every agent has an HTTP endpoint. Send it a message, and read the reply. It speaks A2A 1.0, so A2A SDKs and other agent platforms work too.

To start, open the agent's A2A tab. It shows the endpoint, your token, and curl examples for that agent.

The A2A tab of an agent, showing its endpoint URL and the token used to call it

Endpoints

MethodPathPurpose
POST/v2/a2a/{agentId}Send messages and manage tasks (JSON-RPC)
GET/v2/a2a/{agentId}/.well-known/agent-card.jsonThe agent's AgentCard: name, description, and capabilities
GET/v2/a2a/agentsThe AgentCards of every agent your token can reach

Give clients the full AgentCard URL. The card lives under each agent, not at the domain root. A request to /.well-known/agent-card.json on the host gets a 401, which looks like a token problem.

Authentication

Send a bearer token in the Authorization header of every request. A2A takes the same tokens as the MCP Gateway:

CredentialWhere to get itRuns as
Personal tokenClick your name in the sidebar to open Personal SettingsYou
Team tokenSettings → Teams, then the team's tokenThe team
Organization tokenSettings → AuthThe organization
OAuth access tokenAn OAuth client that lists the agentThe client, or the signed-in user
Identity provider JWTBind the agent to an identity providerThe user in the JWT

What to know:

  • A token reaches only the agents its owner can use. See Access Control.
  • LLM API keys and virtual keys do not work here.
  • GET /v2/a2a/agents takes platform tokens only.

Sending a Message

SendMessage runs one turn and waits for the reply:

bash
curl -X POST "https://archestra.example.com/v2/a2a/<agentId>" \
  -H "Authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "id": 1,
    "method": "SendMessage",
    "params": {
      "message": {
        "role": "ROLE_USER",
        "parts": [{ "text": "Summarize yesterday'\''s open incidents." }]
      }
    }
  }'

The reply is the agent's message:

json
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "message": {
      "role": "ROLE_AGENT",
      "contextId": "327a5306-c7dc-4e0c-ba2f-107da6c2548b",
      "parts": [{ "text": "Two incidents are open..." }]
    }
  }
}

Some calls return a task, not a message: an agent with a dedicated runtime, a tool call that needs approval, or a background run. A finished task holds the answer in its text artifact agent-response. messageId is optional.

Continuing a Conversation

Copy contextId from the first reply into the next message. The agent sees the earlier turns:

json
"message": {
  "role": "ROLE_USER",
  "contextId": "327a5306-c7dc-4e0c-ba2f-107da6c2548b",
  "parts": [{ "text": "Which one is oldest?" }]
}

Use only IDs that Archestra returned. Do not send taskId on a new turn, because a finished task takes no more messages.

Running in the Background

Set configuration.returnImmediately to get a task back at once instead of waiting for the answer:

json
"params": {
  "message": { "role": "ROLE_USER", "parts": [{ "text": "Audit every open PR." }] },
  "configuration": { "returnImmediately": true }
}

The result is a task in TASK_STATE_SUBMITTED. Poll it with GetTask until its state is TASK_STATE_COMPLETED, TASK_STATE_FAILED, or TASK_STATE_CANCELED:

json
{ "jsonrpc": "2.0", "id": 2, "method": "GetTask", "params": { "id": "<taskId>", "historyLength": 0 } }

historyLength: 0 leaves out the history. A failed task gives the reason in status.message. A dropped connection does not stop a task. Only CancelTask does.

Streaming

SendStreamingMessage takes the same params as SendMessage and returns a text/event-stream (use curl -N). Send the A2A-Version: 1.0 header to get the A2A 1.0 event shape:

text
data: {"jsonrpc":"2.0","id":1,"result":{"task":{"id":"...","status":{"state":"TASK_STATE_SUBMITTED"}}}}
data: {"jsonrpc":"2.0","id":1,"result":{"statusUpdate":{"status":{"state":"TASK_STATE_WORKING"}}}}
data: {"jsonrpc":"2.0","id":1,"result":{"artifactUpdate":{"artifact":{"name":"agent-response","parts":[{"text":"Two "}]}}}}
data: {"jsonrpc":"2.0","id":1,"result":{"statusUpdate":{"status":{"state":"TASK_STATE_COMPLETED"}}}}

What to know:

  • Join the artifactUpdate text to build the answer. Skip lines that do not start with data:, such as : keep-alive.
  • Without the header, the stream uses the older A2A 0.3 shape. It ends with a final: true status update.
  • If the connection drops, call SubscribeToTask with the task id to join again.

Approving Tool Calls

When a tool call needs approval, the result is a task in TASK_STATE_INPUT_REQUIRED. The pending requests are in metadata.approvalRequests:

json
"metadata": {
  "approvalRequests": [
    { "approvalId": "appr-1", "toolName": "send_email", "approved": false, "resolved": false }
  ]
}

Answer with a SendMessage that names the task and carries a decision for each request:

json
"message": {
  "role": "ROLE_USER",
  "taskId": "<taskId>",
  "contextId": "<contextId>",
  "parts": [],
  "metadata": {
    "taskOps": { "approvalDecisions": [{ "approvalId": "appr-1", "approved": true }] }
  }
}

The run resumes once every request has a decision. CancelTask on a waiting task cancels it.

Other Methods

MethodParamsWhat it does
ListTaskscontextId, status, pageSize, pageToken (all optional)Your tasks for this agent, newest first
CancelTaskidStops a task
SubscribeToTaskidRejoins a running task's event stream
CreateTaskPushNotificationConfigtaskId, pushNotificationConfig.urlPOSTs each status change of the task to your https URL

Push URLs must be public https addresses. A delivery can arrive twice, so your receiver must handle repeats. Manage push configs with GetTaskPushNotificationConfig, ListTaskPushNotificationConfigs, and DeleteTaskPushNotificationConfig.

SDKs

The A2A SDKs work with /v2/a2a: a2a-python and the 1.x a2a-js for TypeScript. Point the client at the agent's AgentCard URL and pass the token as a bearer header. To let an Archestra agent call another A2A agent, see External Agents.

Plain JSON Payloads

POST /v1/a2a/{agentId} also accepts any JSON body that is not a JSON-RPC envelope, from a tool such as Zapier, for example. Archestra sends the body to the agent as text, as the user message. Each call starts a new conversation.

Troubleshooting

Errors come back with HTTP status 200 and a JSON-RPC error object. Only AgentCard and registry requests use HTTP 401.

ErrorCause
-32600 Authorization header requiredNo Authorization: Bearer header
-32602 Failed to resolve actor from tokenThe token is invalid or cannot reach this agent
-32601 Method not foundA method name from another A2A version, such as message/send
-32600 Invalid RequestThe params do not match the schema. data names the field, for example a role that is not ROLE_USER
-32602 Context not foundA contextId that Archestra did not create, or that belongs to someone else
-32004 the task is in a terminal stateA message sent to a finished task. Send contextId without taskId
-32009 Unsupported A2A-VersionAn A2A-Version header other than 0.3 or 1.0
-32603 Internal errorThe run failed, for example at the LLM provider. data.reason has the provider's message