Skip to main content
A2A lets external systems talk to a Pinkfish agent using the open Agent-to-Agent protocol (v0.3.0) — a JSON-RPC 2.0 standard for agent interoperability. When you enable A2A on an agent, any A2A-compatible client can fetch the agent’s agent card, discover its skills, and send it messages. Use A2A when the caller is itself an agent or an A2A-aware framework. If you just want a plain “POST text, get text” webhook, use the simpler API channel instead.

Enable A2A

  1. Open the agent and go to the Channels tab.
  2. Toggle A2A on. This sets a2aEnabled on the agent and makes its agent card publicly discoverable.
  3. Create an A2A API key for the agent (prefix pf_a2a_). Keys are scoped to a single agent and are shown in full only once at creation. An agent can have up to 20 keys.
Optional settings:
  • Skill allowlist — restrict which of the agent’s skills are advertised on the agent card.
  • Auto-approve tools — when on, A2A calls bypass interactive tool-approval gates (use carefully).
  • End-user connections — require a verified end-user token so each external caller acts as their own connected identity.

Discover the agent (agent card)

A2A clients start by fetching the agent card, which is public (gated only by the A2A toggle) and describes the agent and how to call it:
curl -s "https://<a2a-host>/a2a/{agentId}/.well-known/agent-card.json"
{
  "name": "Research Assistant",
  "description": "Researches topics and summarizes findings",
  "protocolVersion": "0.3.0",
  "url": "https://<a2a-host>/a2a/{agentId}",
  "preferredTransport": "JSONRPC",
  "capabilities": { },
  "securitySchemes": { "ApiKey": { } },
  "security": [ { "ApiKey": [] } ],
  "skills": [ ],
  "defaultInputModes": ["text/plain"],
  "defaultOutputModes": ["text/plain"]
}
The agent card is the source of truth for the call URL: clients should read the JSON-RPC endpoint from the card’s url field rather than hardcoding a host. The card is cached with a 60-second Cache-Control and an ETag.

Send a message

Call the JSON-RPC endpoint from the card’s url with the message/send method. Authenticate with the agent’s A2A key in the X-Api-Key header:
curl -s -X POST "https://<a2a-host>/a2a/{agentId}" \
  -H "X-Api-Key: pf_a2a_YOUR_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "id": 1,
    "method": "message/send",
    "params": {
      "message": {
        "kind": "message",
        "messageId": "11111111-1111-1111-1111-111111111111",
        "role": "user",
        "parts": [
          { "kind": "text", "text": "Research the latest developments in quantum computing" }
        ]
      }
    }
  }'
parts can be text, file (by URI), or structured data.

Response

A terminal reply comes back as an A2A message:
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "kind": "message",
    "messageId": "22222222-2222-2222-2222-222222222222",
    "contextId": "auto_xyz789",
    "role": "agent",
    "parts": [ { "kind": "text", "text": "Here are the latest developments..." } ]
  }
}
If the agent pauses (for example, it needs tool approval or an end-user connection), the result is a task with a non-terminal status.state such as input-required or auth-required. Resume by calling message/send again with the same contextId (see below).

Maintaining conversation context

A2A carries the conversation handle in contextId (the A2A equivalent of a chat ID):
  • First message — omit contextId. The server creates a chat and returns its contextId in the result.
  • Follow-up messages — set params.message.contextId to the value you got back. The agent reuses that chat and sees the full history.
A contextId is bound to the agent (and, when end-user connections are enabled, to the specific end user) that created it. A caller cannot resume a chat that belongs to a different agent or a different end user — those requests fail closed.

Authentication summary

HeaderPurpose
X-Api-KeyThe agent-scoped A2A key (pf_a2a_…). Required. Each key works for exactly one agent.
X-Selected-OrgOptional org context.
X-End-User-TokenA verified end-user bearer token. Required only when the agent has end-user connections enabled.
A2A keys are per-agent and non-transferable: the key’s signed scope (a2a-agent:<agentId>) must match the agent in the URL, so one agent’s key cannot call another agent.

Supported methods

MethodStatus
message/sendSupported (synchronous).
message/streamNot yet implemented — returns MethodNotFound (-32601).
tasks/get, tasks/cancel, tasks/pushNotificationConfig/*Not yet implemented.
Because the current implementation is synchronous, the server returns either a terminal message or a paused task inline; clients drive multi-step flows with follow-up message/send calls that share a contextId.

Error codes

A2A uses JSON-RPC error objects. The HTTP status is 200 for protocol-level errors (the error is in the envelope), 403 for auth failures, and 404 when the agent is missing or not A2A-enabled.
CodeMeaning
-32700Parse error — invalid JSON.
-32600Invalid request — jsonrpc must be "2.0".
-32601Method not found.
-32602Invalid params — e.g. empty message.parts.
-32603Internal error — agent execution failed.
-32010Unauthenticated.
-32011Agent disabled (A2A not enabled).
-32012Rate limited.