A2A Gateway
Overview
A2A (Agent2Agent) is an open protocol that lets AI agents from different providers exchange tasks over a standard interface. In Apinizer, A2A is a first-class API proxy type — you create an A2A Gateway the same way you'd create a REST, SOAP, or AI Gateway, and configure its behavior on a dedicated routing tab. An A2A Gateway works in one of two directions:
- Expose Agent — the proxy publishes itself as an A2A agent, backed directly by its own LLM configuration
- Passthrough — the proxy forwards tasks through to an external A2A agent, applying skill filtering and agent-card rewriting along the way
The A2A Gateway menu item takes you to a card-based list of your A2A Gateways, the same layout used for AI Gateways — open a card to reach that proxy's routing, policies, and trace/traffic/analytics/tasks tabs.
Coming from an older release? A2A used to be configured on a separate "Inbound Agent" screen with its own authentication settings, reachable at a dedicated path. That model has been replaced entirely — see Migrating from the Previous Model. New to agent-to-agent concepts? See AI Fundamentals for a primer.
Quick Start
Create a new A2A Gateway the same way you'd create any other API proxy: give it a name and a single client-facing path.
Open the proxy's A2A Routing tab and pick Expose Agent or Passthrough.
For Expose Agent, set the LLM backend on the proxy's AI Routing tab (required before you can save) and describe the agent's skills on the A2A Routing tab. For Passthrough, add one or more external agents directly on the routing tab (endpoint and authentication) and, optionally, restrict which of their discovered skills are advertised.
Attach any of Apinizer's regular authentication policies (API Key, JWT, OAuth2, ...) to the proxy — the same way you would on any other proxy type.
Deploy the proxy. Its client path becomes the single endpoint A2A clients connect to, for both discovery and task submission.
Point an A2A client at the proxy's path — it fetches the agent card from the standard discovery path, then sends tasks over that same path.
Modes
Expose Agent
An Expose Agent proxy is the agent — there's no separate backend proxy reference to configure. Its LLM backend is the proxy's own AI Routing configuration, and the five guardrail policies — Personal Data Masking, Prompt Protection, Data-Loss Protection (DLP), Off-Topic Protection, and Retry-Storm (Loop) Protection — apply to A2A traffic the same way they do on a regular AI Gateway. AI-Gateway-only policies (Semantic Cache, Token Quotas, Prompt Decorator, Prompt Templates, RAG Injection, Context-Integrity Protection) are not available here, even in Expose Agent mode — see Guardrail Policies below.
Passthrough
Forwards tasks to an external agent, defined directly on the proxy's A2A Routing tab — rewriting the fetched agent card (hostname, advertised authentication scheme, and skill list) before handing it to the caller.
Once an agent's endpoint is saved, Apinizer fetches and previews its agent card automatically.
Leave it empty to advertise every discovered skill, or restrict which ones this proxy exposes.
Each agent is probed periodically and reports Healthy, Down, or Unknown status with its last response time.
Discovery and task calls can't reach cloud-metadata endpoints, loopback, or link-local addresses — see Security and Governance.
A2A Agents Are Configured Inline
There's no standalone "A2A connection" screen to visit first — an external agent is defined at the exact place it's used:
- On a Passthrough proxy's A2A Routing tab, where it can be one of several aggregated agents for discovery (see Multi-Target Aggregation).
- Inside the A2A Call (LLM) / A2A Call (Fixed) policy, as a single agent a model delegates a sub-task to as part of any AI Gateway's own tool-call loop — no A2A Gateway required for that path at all.
Each definition carries its own endpoint, authentication — including an OAuth2 client-credentials flow for agents that require one, acquired automatically at runtime — discovered skill catalog, health status, and approved-catalog fingerprint. Nothing is shared by reference between proxies or policies.
The endpoint you enter is the address tasks are sent to. Its agent card is looked for at that same address first, and if the card isn't served there, at the standard discovery path below it (.../.well-known/agent-card.json) — so entering an agent's task endpoint is enough for discovery to work, and entering its card URL directly keeps working as before.
Applying a Backend Agent: Apply to List → Save → deploy
You add or edit a backend agent in the drawer that opens from the right of the row. The drawer's Apply to List button writes the change to the table only — nothing reaches the server at that step. To persist it you must press the Save button at the bottom of the tab; while unsaved changes exist a warning sits at the top of the tab, and it clears only once the save succeeds. The order is: Apply to List → Save → deploy. Skip the middle step and the table shows the new agent while the gateway keeps serving the old configuration.
The gateway always serves the last deployed configuration. Saving the A2A Routing tab does not by itself change what callers see; backend agents, the published skill catalog and the routing mode reach clients only after you redeploy the proxy to that environment. When saved-but-undeployed changes exist, a warning banner naming the affected environments appears at the top of the A2A Routing tab, and the deploy button at the top of the page switches to Redeploy so both indicators agree.
Outbound Agent Call
When you want to send a task from Apinizer to an external A2A agent, the component that actually delivers it is the A2A Call (LLM) / A2A Call (Fixed) policy (attached to an AI Gateway). As with Passthrough mode, the target agent is defined inline, on the policy's own screen:
Attach the A2A Call (LLM) policy to an AI Gateway.
In the A2A Agent (Inline) section, enter the endpoint, authentication, and mTLS settings if required.
The Discover Skills button connects to the agent, fetches its agent card, and confirms its skill list — it runs before you save, so there's no separate "test connection" step.
Leave it empty to allow every discovered skill; to restrict, pick from the Allowed Skills list.
This agent definition is subject to the same SSRF protection as Passthrough mode (see Security and Governance). The policy screen's A2A Connection field is kept for backward compatibility: it's disabled once an inline agent is defined, and only one of the two is ever used at runtime.
This policy can also be added and updated through the APIops REST API — see API Reference: Policies.
Agent Card, Task Lifecycle, and Streaming
Agent Card
Every A2A Gateway publishes a self-describing agent card, unauthenticated, at the proxy's client path plus /.well-known/agent-card.json — required so a client can discover the agent before it has credentials. The card includes the agent's name, description, skills, and supported input/output modalities, plus an advertised authentication scheme derived automatically from the proxy's own authentication policies (JWT and OAuth2 are reflected as bearer/OAuth2 schemes, Basic as a basic scheme) — an unauthenticated proxy's card advertises no scheme at all. There's no separate per-agent auth-mode selector anymore, and the card can never claim a scheme the gateway doesn't actually enforce. An authenticated client can also fetch the same card over the JSON-RPC channel.
In Passthrough mode the rewritten card's documentationUrl advertises this proxy's own full gateway address — the environment's access URL, the Apinizer root context, and the proxy's client path — rather than the backend agent's, so a client that follows it reaches the gateway. On an environment with no access URL configured the field is root-relative — the Apinizer root context plus the proxy path; where neither is configured it falls back to the proxy path on its own.
Protocol Version
The only A2A protocol version Apinizer speaks is 1.0 (the field is kept for a future version expansion) — unlike MCP, there's no version to choose.
Task Submission and Lifecycle
A client starts a task with SendMessage. In Expose Agent mode Apinizer accepts it and returns a task ID immediately, then works it in the background; in Passthrough mode the backend agent creates and owns the task, and its answer — task ID included — is returned to the client unchanged.
| State | Meaning |
|---|---|
| Submitted | Received, processing not yet started |
| Working | Being processed |
| Completed | Finished successfully |
| Failed | Ended with an error |
| Canceled | Canceled before completion |
In Expose Agent mode, Apinizer's own agent only ever advances a task through submitted → working → completed / failed / canceled / rejected. The remaining two states (input-required, auth-required) are never produced by Apinizer's own agent — they can only be observed on external agents Apinizer talks to as an outbound client.
A client polls status with GetTask, lists a proxy's tasks with ListTasks, and can cancel an in-progress task with CancelTask — cancellation actually interrupts the task's processing on the worker, not just its recorded status.
In Passthrough mode the backend agent owns the tasks it creates, so GetTask and CancelTask resolve in two steps: the proxy first looks for a task it tracks itself (a streaming relay is tracked by the gateway), and if the ID isn't one of those, the call is forwarded to the backend agent and its answer is returned as-is — including its own "task not found" if the ID is unknown there too. This is what lets a client poll the exact task ID a Passthrough SendMessage returned. Whether a given task ID may be read or canceled is decided by the backend agent, the same way it decides authorization for a delegated message. ListTasks and SubscribeToTask always answer from the gateway's own task records and are not forwarded; on a proxy that aggregates more than one agent, GetTask and CancelTask return an error rather than guessing which agent owns the task.
The gateway's own task records are automatically cleaned up some time after reaching a terminal state (completed/failed/canceled/rejected); active tasks are retained indefinitely. A task created by a non-streaming Passthrough call is retained for as long as its backend agent keeps it.
Streaming
A client can request streaming task updates with SendStreamingMessage, delivered over Server-Sent Events. If the connection drops, SubscribeToTask replays the task's stored history so the client can pick up from where it left off.
Push Notifications
For long-running tasks, a client can register a webhook with CreateTaskPushNotificationConfig — Apinizer calls it (with an authentication token) once the task reaches a terminal state, so the client doesn't have to keep a connection open or poll for the result.
Multi-Modality Task Parts
A task can carry parts beyond plain text — image and structured data parts are also supported.
Supported task part types are text, structured data, and image. Audio and video are not covered.
Multi-Target Aggregation
A Passthrough proxy can aggregate up to 10 agents on its A2A Routing tab behind one endpoint, but only for discovery: their skills are merged into a single advertised agent card, with a colliding skill name resolved deterministically the same way MCP tool names are. Sending an actual task is different — the A2A protocol gives a message no field to say which agent it's meant for, so once more than one agent is configured, SendMessage returns an explicit error rather than guessing which agent should receive it. Configure more than one agent only if you want a combined skill catalog for discovery; keep exactly one agent if you intend to actually delegate tasks through the proxy.
Security and Governance
Authentication
Same model as MCP: whatever policy chain you attach to the proxy. The agent-card discovery endpoint is exempt from it by design.