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

# Connect agents through the AI Gateway

> Connect external A2A agents to Orq.ai, invoke them through the Responses API, and expose internal Agents through A2A transports.

Use the **Agents Gateway** to connect [A2A Protocol](https://a2a-protocol.org/latest/) agents in both directions:

<CardGroup cols={2}>
  <Card title="Call an external agent" icon="arrow-up-right-from-square" href="#connect-an-external-a2a-agent">
    Register a remote A2A endpoint, then invoke it through the **AI Gateway** Responses API with `model: "agent/<key>"`.
  </Card>

  <Card title="Expose an internal Agent" icon="share-nodes" href="#expose-an-internal-agent-through-a2a">
    Give A2A clients a per-Agent endpoint backed by an internal **Orq.ai** Agent.
  </Card>
</CardGroup>

Both directions use **Orq.ai** API keys, project scope, rate limits, and traces.

## Connect an external A2A agent

Registering an external Agent fetches and validates its Agent Card before saving the connection. **Orq.ai** caches the card for display and discovery metadata, while each invocation discovers the current card before selecting a transport.

### Register through AI Studio

<Steps>
  <Step title="Open the Agent creator">
    Open a Project or folder in **AI Studio**, select <Icon icon="plus" />, select **Agent**, then select **Connect External Agent**.
  </Step>

  <Step title="Enter the connection">
    Enter an Agent key, display name, Agent URL, and optional Agent Card URL. Leave the protocol version and preferred transport empty to select a compatible interface from the card automatically.
  </Step>

  <Step title="Add authentication headers">
    Add up to 20 outbound headers. Keep **Encrypt** enabled for credentials and other secrets.
  </Step>

  <Step title="Create the Agent">
    Select **Create agent**. Registration succeeds only when the Agent Card is reachable, valid, and advertises the requested protocol and transport.
  </Step>
</Steps>

Open the external Agent in **Agent Studio** to edit its connection, select **Test connection**, or refresh the cached Agent Card. Publish connection edits before testing because the test uses the stored configuration. A connection test fetches the live card without persisting it. Refreshing the card replaces the cached metadata for the stored connection.

### Register through the API

Use an API key with the `a2a.create` permission:

```bash cURL theme={"theme":{"light":"github-light","dark":"github-dark"}}
curl -X POST https://api.orq.ai/v2/agents/external \
  -H "Authorization: Bearer $ORQ_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "key": "remote-support",
    "display_name": "Remote Support",
    "description": "Support Agent hosted outside Orq.ai",
    "path": "Default/agents",
    "agent_url": "https://agents.example.com/support",
    "headers": {
      "Authorization": {
        "value": "Bearer remote-agent-token",
        "encrypted": true
      }
    },
    "protocol_version": "1.0",
    "preferred_transport": "JSONRPC"
  }'
```

Omit `card_url` to discover the card from `agent_url`. Omit `protocol_version` and `preferred_transport` to select the first compatible interface advertised by the card.

<Info>
  Encrypted header values are encrypted at rest and returned as empty strings from read operations. When updating an existing encrypted header, send an empty value to preserve the stored secret. Send the complete desired `headers` map because the update replaces the map.
</Info>

Manage external Agents with these endpoints:

| Operation | Endpoint | Permission |
| - | - | - |
| Create | `POST /v2/agents/external` | `a2a.create` |
| List | `GET /v2/agents/external` | `a2a.list` |
| Retrieve by key or ID | `GET /v2/agents/external/{agent_key}` | `a2a.view` |
| Update | `PATCH /v2/agents/external/{agent_key}` | `a2a.update` |
| Delete | `DELETE /v2/agents/external/{agent_key}` | `a2a.delete` |
| Refresh the cached card | `POST /v2/agents/external/{agent_key}:refreshCard` | `a2a.update` |
| Test the stored connection | `POST /v2/agents/external/{agent_key}:testConnection` | `a2a.view` |

List requests accept `limit`, `starting_after`, and `ending_before`. Do not send both cursor fields in the same request.

Update a connection and revalidate it:

```bash cURL theme={"theme":{"light":"github-light","dark":"github-dark"}}
curl -X PATCH https://api.orq.ai/v2/agents/external/remote-support \
  -H "Authorization: Bearer $ORQ_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "agent_url": "https://agents.example.com/support/v2",
    "protocol_version": "1.0",
    "preferred_transport": "HTTP+JSON"
  }'
```

Test or refresh the saved connection:

<CodeGroup>
  ```bash Test connection theme={"theme":{"light":"github-light","dark":"github-dark"}}
  curl -X POST https://api.orq.ai/v2/agents/external/remote-support:testConnection \
    -H "Authorization: Bearer $ORQ_API_KEY" \
    -H "Content-Type: application/json" \
    -d '{}'
  ```

  ```bash Refresh card theme={"theme":{"light":"github-light","dark":"github-dark"}}
  curl -X POST https://api.orq.ai/v2/agents/external/remote-support:refreshCard \
    -H "Authorization: Bearer $ORQ_API_KEY" \
    -H "Content-Type: application/json" \
    -d '{}'
  ```
</CodeGroup>

## Invoke an external Agent

Call a registered external Agent through the standard Responses API. Keep the `agent/` model prefix:

```bash cURL theme={"theme":{"light":"github-light","dark":"github-dark"}}
curl -X POST https://api.orq.ai/v3/router/responses \
  -H "Authorization: Bearer $ORQ_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "agent/remote-support",
    "input": "Summarize the open support cases."
  }'
```

The **AI Gateway** maps text, image URLs, file URLs, and base64 file input into A2A message parts. Remote text artifacts become Responses API assistant messages. Structured A2A data parts become JSON text. Token usage is reported as zero because the remote Agent does not provide **Orq.ai** model usage.

### Stream output

Set `stream: true` to receive standard Responses API server-sent events:

```bash cURL theme={"theme":{"light":"github-light","dark":"github-dark"}}
curl -N -X POST https://api.orq.ai/v3/router/responses \
  -H "Authorization: Bearer $ORQ_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "agent/remote-support",
    "input": "Summarize the open support cases.",
    "stream": true
  }'
```

When the live Agent Card advertises streaming, the gateway maps A2A artifact and status updates to Responses API events. When the card does not advertise streaming, the gateway completes a blocking A2A call and emits a compatible synthetic Responses stream.

### Continue an interrupted task

When a remote task returns `input_required` or `auth_required`, the Responses API returns an incomplete response. Pass that response ID as `previous_response_id` to continue the same A2A context:

```bash cURL theme={"theme":{"light":"github-light","dark":"github-dark"}}
curl -X POST https://api.orq.ai/v3/router/responses \
  -H "Authorization: Bearer $ORQ_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "agent/remote-support",
    "previous_response_id": "resp_01K6D8QESESZ6SAXQPJPFQXPFT",
    "input": "Use the enterprise account."
  }'
```

The gateway keeps the remote context and task identifiers private. Store the **Orq.ai** response by leaving response storage enabled before using `previous_response_id`.

### External Agent limits in v1

External execution in v1 uses a narrow contract:

* The remote A2A mapping supports `input`, `stream`, and `previous_response_id`. Gateway-managed controls such as response storage still apply.
* Accepted input: a string or user messages containing text, image URLs, file URLs, or base64 file data.
* Unsupported request controls include caller-supplied `tools`, `tool_choice`, retries, fallbacks, load balancing, sampling parameters, background mode, and non-default output shaping.
* `instructions` are not applied to the remote Agent. Configure its behavior at the remote endpoint.
* Remote file output parts are not mapped in v1. Return text or structured data parts.
* Failed and rejected A2A tasks map to failed Responses. Canceled tasks map to canceled Responses. Input-required and auth-required tasks map to incomplete Responses.

## Expose an internal Agent through A2A

Every internal **Orq.ai** Agent has an A2A endpoint. Open the Agent in **Agent Studio**, expand **Expose via A2A**, then copy the Agent URL, Agent Card URL, and required `a2a.execute` permission.

<Warning>
  Do not use an external Agent registration as an ingress endpoint. Only internal **Orq.ai** Agents can be exposed through the A2A gateway.
</Warning>

### Discover the Agent Card

Fetch the standard Agent Card path with a scoped **Orq.ai** API key:

```bash cURL theme={"theme":{"light":"github-light","dark":"github-dark"}}
curl https://api.orq.ai/v2/a2a/my-agent/.well-known/agent-card.json \
  -H "Authorization: Bearer $ORQ_API_KEY"
```

The card advertises A2A 1.0 JSON-RPC, HTTP + JSON, and gRPC interfaces, text input and output, streaming support, bearer authentication, and the Agent's published skills.

### Send a JSON-RPC message

The base endpoint defaults to the A2A 0.3 compatibility contract when `A2A-Version` is absent. Set `A2A-Version: 1.0` for the A2A 1.0 contract.

<CodeGroup>
  ```bash A2A 1.0 theme={"theme":{"light":"github-light","dark":"github-dark"}}
  curl -X POST https://api.orq.ai/v2/a2a/my-agent \
    -H "Authorization: Bearer $ORQ_API_KEY" \
    -H "A2A-Version: 1.0" \
    -H "Content-Type: application/json" \
    -d '{
      "jsonrpc": "2.0",
      "id": "request-1",
      "method": "SendMessage",
      "params": {
        "message": {
          "messageId": "message-1",
          "role": "ROLE_USER",
          "parts": [{"text": "Summarize the account."}]
        }
      }
    }'
  ```

  ```bash A2A 0.3 compatibility theme={"theme":{"light":"github-light","dark":"github-dark"}}
  curl -X POST https://api.orq.ai/v2/a2a/my-agent \
    -H "Authorization: Bearer $ORQ_API_KEY" \
    -H "A2A-Version: 0.3" \
    -H "Content-Type: application/json" \
    -d '{
      "jsonrpc": "2.0",
      "id": "request-1",
      "method": "message/send",
      "params": {
        "message": {
          "messageId": "message-1",
          "role": "user",
          "parts": [{"kind": "text", "text": "Summarize the account."}]
        }
      }
    }'
  ```
</CodeGroup>

Unsupported `A2A-Version` values return `400`.

### Use another A2A transport

| Binding | Endpoint |
| - | - |
| JSON-RPC | `POST /v2/a2a/{agent_key}` |
| HTTP + JSON | `/v2/a2a/{agent_key}/message:send`, `/message:stream`, `/tasks`, and `/tasks/{task_id}` |
| Connect or gRPC-Web | `/v2/a2a/{agent_key}/lf.a2a.v1.A2AService/{Method}` |
| Native gRPC | `lf.a2a.v1.A2AService` with the Agent key in the request `tenant` field |

Send the API key as `Authorization: Bearer <token>` for HTTP, Connect, and gRPC metadata. The API key must include `a2a.execute` and access to the Agent's Project. Authentication, project scope, quota, and rate limits apply before execution.

### Ingress limits in v1

* Blocking and streaming message execution are supported.
* Task retrieval and task listing are supported for stored Responses that belong to the routed Agent.
* Non-blocking execution is not supported.
* Task cancellation and task subscriptions are not supported.
* Push notification configuration and extended Agent Cards are not supported.
* Agent Cards advertise `streaming: true` and `pushNotifications: false`.

## Security controls

External Agent registration and execution apply the following controls:

* HTTPS is required for Agent, card, and advertised interface URLs.
* Loopback, private, link-local, metadata, and unique-local network targets are blocked before connection, including alternate numeric IP forms and DNS answers that resolve to blocked ranges.
* Redirects are not followed.
* Agent Card size and fetch time are bounded.
* Encrypted headers are masked at API boundaries. Runtime trace headers are managed by **Orq.ai** and cannot be overridden by stored connection headers.
* Stored headers are sent only to interfaces on the configured agent or card origin. Other advertised interfaces are validated, then excluded before transport selection.
* Project-scoped API keys can only manage, invoke, or expose Agents in allowed Projects.

Plain HTTP is available only for localhost development when both `ENVIRONMENT` is `local` or `development` and `A2A_ALLOW_HTTP_LOCALHOST` is `true`. Keep this setting disabled in deployed environments.

## Self-hosted configuration

| Variable | Service | Default | Purpose |
| - | - | - | - |
| `A2A_PUBLIC_BASE_URL` | Responses API | `http://localhost:<PORT>` locally, otherwise required | Absolute HTTP or HTTPS base used in internal Agent Cards. Outside local environments the A2A ingress is disabled when it is unset |
| `A2A_GRPC_PORT` | Responses API | `9092` | Native A2A gRPC listener port |
| `A2A_GRPC_PUBLIC_URL` | Responses API | unset | Public native gRPC dial target advertised in internal Agent Cards; when unset the card omits the gRPC interface. Use `host:port`, `dns:///host:port`, or `passthrough:///host:port` |
| `A2A_ALLOW_HTTP_LOCALHOST` | Platform API and Responses API | `false` | Allow plain HTTP for localhost only in local or development environments |
| `A2A_CARD_TIMEOUT_SECONDS` | Platform API and Responses API | `10` | Agent Card fetch timeout |
| `A2A_MAX_CARD_BYTES` | Platform API and Responses API | `1048576` | Maximum Agent Card response size |
| `A2A_MAX_HEADERS` | Platform API | `20` | Maximum connection headers stored for an external agent |
| `A2A_INVOKE_TIMEOUT_SECONDS` | Responses API | `300` | Blocking external A2A invocation timeout |
| `A2A_STREAM_IDLE_TIMEOUT_SECONDS` | Responses API | `300` | Maximum idle interval while reading an external A2A stream |

Set every duration, byte limit, and header limit to a positive integer. In deployed environments, set `A2A_PUBLIC_BASE_URL` to the public **AI Gateway** HTTP origin and `A2A_GRPC_PUBLIC_URL` to an externally reachable native gRPC target such as `agents.example.com:443` or `dns:///agents.example.com:443`. Do not include `http://` or `https://` in the gRPC target; clients configure gRPC transport security separately. For authenticated ORQ-to-ORQ gRPC, expose the target through the same public HTTPS host and port as the configured agent or card URL so origin-bound stored headers remain eligible for that interface.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.