Talk to your agents

Talk to your agent graph via A2A (JSON-RPC)

Copy page

Use the A2A JSON-RPC protocol to send messages to your agent graph and receive results, with optional streaming.

The A2A (Agent-to-Agent) endpoint lets external agents/services talk to your agent graph using a JSON-RPC 2.0 protocol compatible with Google's A2A schema.

Authentication

Choose the authentication method:

See Authentication → Run API for more details.

Endpoints

  • Agent card discovery (graph or agent-level): GET /agents/.well-known/agent.json
  • A2A protocol (graph or agent-level): POST /agents/a2a

Notes:

  • If you supply x-inkeep-agent-id in headers, requests target that specific agent. This is supported in development (or when using the bypass secret). With production API keys, requests always use the graph’s default agent. API keys bound to a specific agent are not yet supported.

Message Send (Blocking)

  • Path: POST /agents/a2a
  • Headers: Per Authentication section (Standard API Key recommended)
  • Body (JSON-RPC 2.0):
{
  "jsonrpc": "2.0",
  "method": "message/send",
  "id": 1,
  "params": {
    "message": {
      "messageId": "msg-123",
      "role": "user",
      "parts": [
        { "kind": "text", "text": "Hello!" }
      ],
      "contextId": "conv-123",
      "kind": "message"
    },
    "configuration": {
      "acceptedOutputModes": ["text", "text/plain"],
      "blocking": true
    }
  }
}
  • Success Response (Message):
{
  "jsonrpc": "2.0",
  "result": {
    "kind": "message",
    "messageId": "auto-generated",
    "role": "agent",
    "parts": [ { "kind": "text", "text": "..." } ],
    "taskId": "task-...",
    "contextId": "conv-123"
  },
  "id": 1
}
  • Transfer Case: if the agent decides to transfer, the response contains a task with a transfer artifact:
{
  "jsonrpc": "2.0",
  "result": {
    "kind": "task",
    "id": "task-...",
    "contextId": "conv-123",
    "status": { "state": "completed", "timestamp": "..." },
    "artifacts": [
      {
        "artifactId": "...",
        "parts": [
          { "kind": "data", "data": { "type": "transfer", "targetAgentId": "other-agent-id" } },
          { "kind": "text", "text": "Transfer reason text" }
        ]
      }
    ]
  },
  "id": 1
}

Message Send (Non-blocking)

Set configuration.blocking to false. The server immediately returns a task, and you can poll or stream updates.

  • Request: same as above, with "blocking": false
  • Response (Task):
{
  "jsonrpc": "2.0",
  "result": {
    "kind": "task",
    "id": "task-...",
    "contextId": "conv-123",
    "status": { "state": "completed", "timestamp": "..." },
    "artifacts": [ { "artifactId": "...", "parts": [ { "kind": "text", "text": "..." } ] } ]
  },
  "id": 1
}

Streaming Messages (SSE)

  • Path: POST /agents/a2a
  • Headers: include Accept: text/event-stream plus Authentication headers
  • Body (JSON-RPC 2.0): same as blocking, but method "message/stream"
{
  "jsonrpc": "2.0",
  "method": "message/stream",
  "id": 2,
  "params": {
    "message": {
      "messageId": "msg-456",
      "role": "user",
      "parts": [ { "kind": "text", "text": "Stream please" } ],
      "contextId": "conv-123",
      "kind": "message"
    },
    "configuration": {
      "acceptedOutputModes": ["text", "text/plain"],
      "blocking": false
    }
  }
}
  • SSE Events (each line is an SSE data: payload containing JSON-RPC):
: keep-alive

data: {"jsonrpc":"2.0","result":{"kind":"task","id":"task-...","contextId":"conv-123","status":{"state":"working","timestamp":"..."},"artifacts":[]},"id":2}

data: {"jsonrpc":"2.0","result":{"kind":"message","messageId":"...","role":"agent","parts":[{"kind":"text","text":"..."}],"taskId":"task-...","contextId":"conv-123"},"id":2}

data: {"jsonrpc":"2.0","result":{"kind":"task","id":"task-...","contextId":"conv-123","status":{"state":"completed","timestamp":"..."},"artifacts":[{"artifactId":"...","parts":[{"kind":"text","text":"..."}]}]},"id":2}
  • Transfer (streaming): if a transfer is triggered, an SSE event with a JSON-RPC result of transfer details is sent, then the stream ends.

Task APIs

  • Get task: POST /agents/a2a with method "tasks/get" and params { "id": "task-..." } → returns the task
  • Cancel task: POST /agents/a2a with method "tasks/cancel" and params { "id": "task-..." } → returns { "success": true }
  • Resubscribe (SSE, mock): POST /agents/a2a with method "tasks/resubscribe" and params { "taskId": "task-..." } → SSE with a task event
Note
Note

Currently, tasks/get and tasks/cancel return stubbed responses, and tasks/resubscribe returns a mock SSE event. For live progress updates, use message/stream.

Agent Card Discovery

  • Graph-level: GET /agents/.well-known/agent.json (uses graph default agent)
  • Agent-level (dev/bypass only): Provide x-inkeep-agent-id in headers to target a specific agent for discovery

Notes & Behavior

  • contextId resolution: The server first tries task.context.conversationId (derived from the request), then params.message.metadata.conversationId. Final fallback is 'default'.
  • Artifacts in responses: Message/Task responses may include artifacts[0].parts as the agent's output parts.
  • Errors (JSON-RPC): Standard JSON-RPC error codes: -32600, -32601, -32602, -32603, -32700, plus A2A-specific -3200x codes.

Development Notes

  • Base URL (local): http://localhost:3003
  • Route Mounting: A2A routes are mounted under /agents; use /agents/a2a for RPC and /agents/.well-known/agent.json for discovery
  • Streaming support: Requires agent capabilities streaming: true in the agent card