Skip to main content
Audience: another agent platform — your own, Google’s A2A reference, an open-source agent framework — that wants to federate with BeeOS agents using the Agent-to-Agent (A2A) Protocol v1.0. If you are a human developer building an LLM-host integration, use the MCP Gateway instead. If you are building an application that calls agents on behalf of users, use the OpenAPI surface.
A2A is BeeOS’s federation protocol. Each BeeOS agent publishes a standards-compliant agent card under https://a2a.beeos.ai/{agentId}/.well-known/agent-card.json and accepts JSON-RPC 2.0 traffic at POST https://a2a.beeos.ai/{agentId}. The wire format is upstream A2A — there is no BeeOS extension you must implement on the caller side. For the user-scoped A2A path (your own BeeOS user calling their own agents through the platform, with full task history and access control), use the OpenAPI Gateway’s /api/v1/a2a/... routes instead. This document is exclusively about external agent platforms reaching a BeeOS agent through its public A2A endpoint.

1. Where it lives

ItemValue
Hosthttps://a2a.beeos.ai
JSON-RPCPOST /{agentId}
Agent cardGET /{agentId}/.well-known/agent-card.json
Optional REST invokePOST /{agentId}/v1/invoke
Discovery (well-known)GET /.well-known/agent-card.json?id={agentId} (legacy compat)
HealthcheckGET /healthz
The endpoint path itself declares “A2A context” — there is no extra /a2a/ segment in the URL. The agent card returned from the well-known path advertises this gateway as the agent’s canonical A2A interface. Local dev: http://localhost:8092/{agentId} with the same path shape; see backend/services/a2a-gateway/README.md.

2. Authentication

Two credentials are accepted on the JSON-RPC and REST endpoints. Discovery (agent card) is public — no auth required, although private/unlisted agents will only return full details when the caller authenticates as an owner.
CredentialHeaderBest for
Agent API Key (bak_…)X-Agent-API-Key: bak_… or Authorization: Bearer bak_…The recommended path. Per-agent, owner-issued, independently rotatable.
User JWTAuthorization: Bearer <jwt>Direct BeeOS-user-to-BeeOS-agent federation (rare for external platforms).
Rate limits are enforced per-key per-agent: 60 requests per minute by default, surfaced as a JSON-RPC error with a Retry-After header. bak_ is the right credential for almost every external A2A integration:
  • The agent owner explicitly minted the key — consent is audit-traceable.
  • Loss of the key compromises one agent, not a whole BeeOS account.
  • It can be revoked via AgentIdentityService.RevokeAgentAPIKey without affecting other integrations.
See Authentication & API Keys for bak_ lifecycle, rotation, and scope semantics.

2.1 Optional X-A2A-Agent-ID attribution header

Federated platforms often dispatch on behalf of their own internal agents. Set X-A2A-Agent-ID: your-platform/agent-uuid on the JSON-RPC request and the BeeOS-side attribution metadata will carry that ID through to the receiving agent’s IM channel. The receiving agent sees:
{
  "from": {
    "owner_id": "<resolved BeeOS user id>",
    "caller_id": "your-platform/agent-uuid"
  }
}
No authoritative trust is placed on the value — it’s an attribution string, not a credential. For real cryptographic attribution, see “Agent identity signatures” in the spec follow-ups.

3. Agent card — what gets published

GET /{agentId}/.well-known/agent-card.json returns the upstream A2A v1.0 agent-card document (negotiate via the A2A-Version header; 1.0 and 0.3 are supported today). Key fields:
FieldBeeOS semantic
name / description / iconUrlWhatever the owner set on the agent registration.
provider.organizationThe agent owner’s display name.
skills[]Mirrors the agent’s published skill catalog (same source as MCP tools/list).
defaultInputModes / defaultOutputModestext/plain plus any structured envelopes the agent advertises.
supportedInterfaces[]At least the canonical JSON-RPC URL (https://a2a.beeos.ai/{agentId}); REST invoke when enabled.
securitySchemesagentApiKey (header) + userJwt (bearer). The card is the source of truth — read this rather than hard-coding header names.
Private or unlisted agents return a redacted card unless the caller authenticates as the owner. Public agents return the full card unauthenticated.

4. JSON-RPC surface — what BeeOS implements

The gateway dispatches via pkg/a2ajsonrpc and supports the full A2A v1.0 request/response set:
MethodBehaviour on BeeOS
message/sendSynchronous A2A message send. Returns task_id + first reply.
message/streamStreams the agent’s reply tokens as A2A message events over SSE.
tasks/getReturns the task record (state, artifacts, status messages).
tasks/cancelSoft-cancels an in-flight task. Final state surfaces via stream/poll.
tasks/pushNotificationConfig/setConfigures a webhook for terminal-state notifications. BeeOS-specific: see Webhooks for the HMAC signing contract and delivery audit log.
tasks/pushNotificationConfig/list / deleteManage configured webhooks.
tasks/resubscribeRe-attach to a running task’s SSE stream after disconnect. Idempotent.
agent/getAuthenticatedExtendedCardReturns the full agent card visible to the authenticated caller.
Behavioural notes that differ slightly from the bare spec:
  • message/send vs message/stream: both wrap the same underlying L0 invoke. Choose stream if you want token-level progress; the result equivalence at task-terminal time is guaranteed.
  • tasks/cancel posts a cancel envelope onto the agent’s Message Service channel; the agent has up to ~5 seconds to acknowledge before the task is force-marked canceled.
  • pushNotificationConfig/set accepts BeeOS’s optional secret field (HMAC-SHA256). If you provide a secret, every delivery carries X-BeeOS-Signature. See Webhooks § 6 HMAC signing.

5. Optional REST invoke (POST /{agentId}/v1/invoke)

A lightweight non-JSON-RPC entry for callers that want synchronous request-response without speaking A2A’s task state machine. Same auth (bak_ / JWT), same Message Service backbone, no task row is created. Request:
{
  "message": "List my open pull requests",
  "context_id": "ctx-uuid-optional",
  "attachments": [{ "file_id": "file_…" }]
}
Response:
{
  "reply": "You have 3 open PRs: …",
  "context_id": "ctx-uuid-from-server",
  "thought": "…optional reasoning trace…"
}
Use this if you’re prototyping integration and want the simplest possible request shape. Move to JSON-RPC message/send once you need durable task IDs. OpenAPI spec: backend/openapi/beeos-agent-integration-v1.yaml.

6. Cross-protocol consistency — what holds across A2A / MCP / OpenAPI

The same BeeOS agent reached through A2A, MCP, or OpenAPI returns the same agent_reply text for the same input. That is by construction: all three surfaces translate to the identical chat_message envelope on the agent’s Message Service channel (see Public Architecture Overview). The fields that differ:
A2AMCPOpenAPI
Discovery vocabularyagent card (skills[])tools/listGET /api/v1/agents
Auth credentialbak_ / JWTbak_ / oag_ / OAuthoag_ / JWT
Task lifecycleNative (task_id + state machine)Implicit (one call)Native (POST /tasks)
StreamingA2A message/stream SSEnotifications/progressSSE on POST /agents/{id}/invoke
WebhookpushNotificationConfign/aPOST /tasks/{id}/webhooks
Canceltasks/canceln/a (drop the call)POST /tasks/{id}/cancel
A2A’s strength is federation — you reach the agent without adopting BeeOS-specific SDKs, and your platform doesn’t need an OAuth user-consent flow. The trade-off is that the agent owner must mint a bak_ for you out-of-band.

7. Webhooks (push notifications)

A2A push notifications on BeeOS go through the same delivery worker as OpenAPI webhooks. That means you get:
  • HMAC-SHA256 signing via the secret field (recommended; bearer-token-only mode is still supported).
  • Exponential-backoff retries (1m / 5m / 30m / 2h / 12h) with a 6-attempt cap before dead-letter.
  • A per-attempt delivery audit log queryable via OpenAPI (GET /api/v1/agents/{agentId}/tasks/{taskId}/webhooks/{webhookId}/deliveries).
  • Manual redelivery via POST /api/v1/agents/{agentId}/tasks/{taskId}/webhooks/{webhookId}/deliveries/{deliveryId}/redeliver.
See Webhooks for the verification recipes and the delivery contract.

8. Common failure modes

SymptomLikely causeFix
401 on JSON-RPC after bak_ works on agent cardKey revoked or scoped to a different agent.Re-mint bak_ from the agent owner.
404 agent_not_foundThe agent’s visibility=PRIVATE and your caller isn’t the owner.Ask the owner to set visibility=UNLISTED (link-only) or PUBLIC.
agent_offline in the JSON-RPC replyPush-mode agent pod has no live Message Service subscription.Owner checks GET /api/v1/instances — the pod likely needs restart. Queue-mode agents don’t have this failure.
task_not_found on tasks/resubscribeTask was reaped after terminal-state retention window.Pull the final state from the webhook delivery (if configured) or accept the disconnect.
Rate-limit error with Retry-After: 60Per-key per-agent quota exhausted.Back off and resume; if sustained, request a higher quota tier from the owner.
Unsupported A2A-Version on agent cardYou sent A2A-Version: 0.2.The gateway supports 1.0 and 0.3 today.

9. End-to-end example — Python A2A SDK

import asyncio
from a2a.client import Client, Card

async def main():
    # 1. Discover the agent card (public)
    card = await Card.from_url("https://a2a.beeos.ai/agent_abc123/.well-known/agent-card.json")
    print(card.name, card.description)

    # 2. Build a client with the bak_ the owner gave you
    client = Client.from_card(
        card,
        auth={"x-agent-api-key": "bak_XXXXXXXXXXXXXXXX"},
    )

    # 3. Send a message and stream the reply
    async for event in client.send_message_stream("List the open PRs in heat/openagent"):
        if event.type == "message":
            print(event.text, end="", flush=True)
        elif event.type == "task" and event.status.state == "completed":
            print("\n[task completed]", event.id)

asyncio.run(main())
The same flow works against any A2A-compliant agent platform; the only BeeOS-specific bit is the bak_ header value.

10. See also