Skip to main content

Set up A2A federation between tenants

The A2A federation model explains what federation is; this guide is the working order of operations for standing up a federation edge between two tenants — the peer registration, the handshake that authenticates cross-tenant task traffic, the accept/reject policy on inbound calls, and the audit trail you revoke through when the edge ends.

What a federated request looks like

Orbit speaks the A2A protocol v1.0.0, so a federated edge is not tenant-to-tenant only — your agent can task any A2A-conformant peer, and an A2A client you let in can task your agent. When both ends are Orbit tenants, both directions share one setup shape. A federated request is one prompt handed to a third-party agent: the requesting tenant persists an outbound envelope, signs it, forwards it to a registered peer URL, and polls the returned task id until the peer answers. Context beyond the prompt does not travel — the peer receives the envelope message only.

Register a peer endpoint

A peer is registered because someone hands you their AgentCard URL. On Orbit the agent owner copies it from Agents → → A2A → Copy share URL; that works only after the agent’s discovery mode is public (or tenant, if you share over an authenticated channel). See the discovery-mode table. Register the URL so your agent knows the peer exists:
On add, the platform fetches the card, stores it on the peer row, and surfaces the peer’s skill catalog in the dashboard — that fetch is the capability announcement. If the card is an Orbit card, it carries a signatures[] block (the A2A Signed Agent Card extension) so the peer’s identity is verified without a shared secret. The URL must be a public FQDN over HTTPS — localhost, private IP tiers, and link-local hosts are refused at registration. Two Orbit tenants federate by each registering the other’s AgentCard URL — one call on each side, and the edge is symmetric.

Authenticate the handshake

Every task endpoint — inbound and outbound — requires the HMAC-signed header. AgentCard signatures authenticate the card, not the call.
Sign ${ts}.${raw_body} exactly as sent, within a ±60-second replay window. Share the per-org A2A secret (DEVOTEL_A2A_HMAC_SECRET; it falls back to DEVOTEL_API_SECRET_KEY on fresh deployments) with the peer over a side channel — never in the request itself. If either side rotates the key, re-share before traffic resumes, or every task retries the signature gate (see Troubleshooting: A2A federation).

Send a federated task (outbound)

With a peer in the registry, delegate a task:
The POST persists an outbound row, signs, and forwards. Poll GET …/a2a/tasks/{taskId} (sign over ${ts}., empty body) until the peer answers. What forwards: the skill name and the text parts you include — nothing more. Any tenant, conversation, or contact identifiers you want the peer to act on must be explicit payload fields on the message itself. What does not forward: your conversation history, contact profile fields, memory entries, or metadata of any kind. The receiving agent gets the prompt and runs it against whatever its own tenant owns.

Accept or reject inbound calls

Inbound hits your agent’s task endpoints with a valid signature, only when a signing key is registered — the one signed-envelope boundary is fail-open until the first key is provisioned; after that, every unsigned or mismatched envelope returns a fixed-operator-safe 401. The policy lever you own is per-agent: to expose an agent to peers at all, its discovery mode must be public (or tenant for share-URL-on-a-side-channel). An agent with discovery disabled accepts tasks only from callers who already know its URL — even so, the endpoint never announces “agent exists” to an unauthenticated probe: the public card route answers a flat 404. To reject a peer by policy rather than by signature: nothing rejects inbound on a per-peer basis beyond the shared-secret gate. Revoke the peer from the registry (next section) and rotate the HMAC key — that severs their ability to sign. The fail-open boundary is documented on the concept page; do not ask a peer to send unsigned once a key exists.

Audit the registry and revoke a peer

Peer rows and every inbound/outbound task sit on per-tenant tables (agent_a2a_peers, agent_a2a_tasks), so a federation edge is auditable end-to-end from your side alone.
  • List every edge: GET /api/v1/agents/{agentId}/a2a/peers — the full per-agent peer registry.
  • Revoke an edge: DELETE /api/v1/agents/{agentId}/a2a/peers/{peerId} — removes the row; the peer’s URL stops resolving and outbound tasks to it error at the peer step.
  • Trace the round-trip: GET /api/v1/agents/{agentId}/a2a/tasks lists both directions with status and latency — the audit trail that survives a revocation.
Audit log events agent.a2a.peer_added / agent.a2a.peer_removed fire on each registry mutation, so a peer add or revoke is attributable to an operator.

Worked example: returns-agent ⇄ order-status-agent

A customer-success org runs a returns-agent; its supplier runs an order-status-agent on their own Orbit tenant.
  1. The supplier flips order-status-agent discovery to public and hands over its share URL.
  2. Customer success registers it: POST /agents/returns-agent/a2a/peers with the supplier URL. The returns-agent now sees the supplier’s order_status skill.
  3. A return landed in the success inbox — the operator delegates:
  1. The supplier’s agent answers on its own data; the success tenant polls the returned task id and gets a completed envelope with the status text. Neither side saw the other’s contact records.
When the contract ends, DELETE the peer row and rotate the shared HMAC key.

Errors

The four failure classes — discovery refused, signature rejection, peer errors, registration refused on the URL — map one-to-one to gates you hit above. When one fires, work through Troubleshooting: A2A federation before re-tasking.

See also