> ## Documentation Index
> Fetch the complete documentation index at: https://gateway.forceaisecurity.com/llms.txt
> Use this file to discover all available pages before exploring further.

# A2A agents overview

> Register an external agent as an A2A endpoint in the ForceAI Gateway, then govern and call it like any model.

An A2A agent is an external agent (Snowflake Cortex, Bedrock AgentCore, M365 Copilot, and others) registered in the gateway so you can call it over the A2A protocol through the same governed surface as your models: scoped keys, guardrails, budgets, and full logging. The per-backend guides differ only in auth and the `forceai_params` you register; the lifecycle below is the same for all

## The lifecycle

Every agent follows create, approve, invoke

<Steps>
  <Step title="Create">
    `POST /v1/agents` with the agent name, an A2A agent card, and backend-specific `forceai_params`. The agent lands in `pending`, and a virtual key scoped to it is auto-provisioned
  </Step>

  <Step title="Approve">
    `POST /v1/agents/{agent_id}/approve`. Approval is a required governance step: even an admin must approve an agent before it can be invoked, so "who approved this" stays an auditable answer. On docker-compose, reload or restart the gateway after approval so its in-memory registry picks the agent up
  </Step>

  <Step title="Invoke">
    `POST /v1/a2a/{agent_id}/message/send` with a JSON-RPC `message/send` body. The gateway resolves auth, calls the backend, and logs the request
  </Step>
</Steps>

## Create request shape

```bash theme={null}
curl -X POST https://YOUR_GATEWAY_DOMAIN/v1/agents \
  -H "Authorization: Bearer $ADMIN_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "agent_name": "my-agent",
    "agent_card_params": {
      "protocolVersion": "0.3",
      "name": "My Agent",
      "description": "What this agent does",
      "url": "https://backend-or-placeholder/",
      "capabilities": { "streaming": false },
      "defaultInputModes": ["text"],
      "defaultOutputModes": ["text"],
      "skills": [{ "id": "demo", "name": "Demo", "description": "...", "tags": ["demo"] }]
    },
    "forceai_params": { "...": "backend-specific, see each guide" }
  }'
```

<Warning>
  `agent_card_params.protocolVersion` must be exactly `"0.3"` or `"1.0"`. Any other value (for example `"0.3.0"`) is rejected with HTTP 400
</Warning>

## Invoke request shape

```bash theme={null}
curl -X POST https://YOUR_GATEWAY_DOMAIN/v1/a2a/{agent_id}/message/send \
  -H "Authorization: Bearer $AGENT_SCOPED_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "id": "1",
    "method": "message/send",
    "params": { "message": { "role": "user", "parts": [{ "kind": "text", "text": "hello" }] } }
  }'
```

The response carries the agent reply under `result.artifacts[].parts[].text`. Use `method: "message/stream"` for streaming backends

## The backends

<CardGroup cols={3}>
  <Card title="Snowflake Cortex" icon="snowflake" href="/agents/snowflake-cortex">
    REST bridge to a Cortex Agent, PAT or key-pair JWT
  </Card>

  <Card title="AWS Bedrock AgentCore" icon="aws" href="/agents/aws-agentcore">
    Native A2A runtime, AWS SigV4
  </Card>

  <Card title="Microsoft 365 Copilot" icon="microsoft" href="/agents/m365-copilot">
    Native A2A server, Entra OAuth
  </Card>
</CardGroup>

## After an agent is live

The agent-scoped key auto-provisioned on create is how a consumer calls it. Invocations appear in Logs attributed to the agent's real backend provider (a Cortex agent reads as `snowflake`, an AgentCore agent as `bedrock`), and each row records the backend so history keeps its attribution even after an agent is deleted
