Skip to main content
AgentHeya agents expose a fully spec-compliant Google A2A v0.3.0 endpoint. Any A2A-compatible agent framework — LangGraph, CrewAI, Claude Managed Agents, custom orchestrators — can discover your agent, send tasks, receive streaming responses, and hand off conversations with full history. A2A endpoint: https://a2a.agentheya.com/agent/{agent_id} Every agent has its own endpoint. {agent_id} is your agent’s immutable 10-character id — find it as the A2A Server URL on the dashboard API Keys page, or in Details → A2A / External Agents. Because the id never changes, the endpoint keeps resolving even after you rename the agent (the agent’s link name also works in place of the id).
A global entry point at https://a2a.agentheya.com still exists for backward-compatible callers: POST there with your key and it resolves to the agent that key is bound to. New integrations should prefer the per-agent /agent/{agent_id} URL — its card is publicly discoverable without a key.

Getting an API key

An API key (sk_ah_...) is the only credential needed to call your agent’s A2A endpoint. There are two ways to create one: The programmatic path is designed for agent owners who want to provision keys for partners or integrations without using the dashboard. See Management MCP for the full workflow. All requests to the A2A endpoint must include:

Agent discovery

Before sending tasks, an external agent can read your agent’s capability card. The per-agent card is public — no API key required — so any A2A-aware agent can discover your agent from its URL alone:
The card describes your agent’s name, description, supported input/output formats, capabilities (streaming, push notifications), and example queries, plus the JSON-RPC url to POST tasks to. An API key is only needed to call the agent, not to read its card.
The legacy root card at https://a2a.agentheya.com/.well-known/agent-card.json still works: without a key it returns the generic platform card; with a Bearer sk_ah_... key it returns that key’s agent card. Prefer the per-agent URL above for keyless discovery.

Customising your agent card

From the Details page in your dashboard, expand the A2A / External Agents section to edit:

Sending a task

Non-streaming (message/send)

The response is a complete Task object with an artifacts array containing the agent’s reply. status.state is usually "completed"; when the agent needs more from you to proceed, the task instead parks in "input-required"status.message carries the agent’s question, and you answer by sending a follow-up message/send with the same taskId. Protocol version: this endpoint speaks A2A 0.3 (the default when no A2A-Version header is sent, per the spec). Requests pinning A2A-Version: 1.x receive a -32009 VersionNotSupportedError with supportedVersions: ["0.3"].

Streaming (message/stream)

Same request body, but use message/stream as the method. The response is text/event-stream (SSE). Each data: line is a JSON-RPC response with the same id. Frame sequence:
  1. Task — state = working, artifacts empty
  2. TaskStatusUpdateEvent (repeated) — state = working, message contains text deltas
  3. TaskArtifactUpdateEvent (per file, if any)
  4. TaskStatusUpdateEvent — state = completed, final: true

Multi-turn conversations

Use contextId to group related tasks into a conversation thread — a new task created with an existing contextId is seeded with the previous task’s conversation, so the agent remembers the thread across tasks. Use taskId to continue an existing non-terminal task (i.e. one parked in input-required); terminal tasks reject follow-ups per the A2A spec:
The agent sees all prior turns in the task’s history, so follow-up questions have full context.

Handing off a conversation

When an external agent wants to hand off a conversation mid-flight — with full history — it passes the prior turns in message.metadata['x-handoff-history']:
Two formats accepted:
  • Simple{ role: "user"|"assistant"|"agent", content: string } — easiest for non-A2A callers
  • Native A2A — full A2A Message objects with parts arrays
Up to 100 prior turns are accepted. They’re prepended into the task’s history so the receiving agent has the full conversation context before it responds.

Handing back

Two mechanisms, depending on how the conversation arrived:
  • Plain delegation (no handoff envelope): hand-back is implicit in the task lifecycle. When the task reaches completed, the calling agent polls tasks/get or receives a push notification and continues from there. Use the same contextId across both agents to keep the thread logically connected.
  • Bridged handoff (the message carried an agentheya.handoff/v1 envelope — see Peer patterns): the receiving agent gets a handoff_release tool. Calling it stamps agentheya/handoff-release metadata (with outcome, summary, and return_values validated against the originator’s expected_return contract) on the response message AND POSTs the originator’s resume.a2a_callback, so both blocking and async originators learn the conversation is theirs again.
The receiving agent can also park the task in input-required (via its request_caller_input tool) when it needs something only the calling side can provide — answer on the same taskId to resume.

Files

Sending files to the agent

Include FilePart entries in message.parts:
Or by URL:
Files are saved to the agent’s storage and made available to its file-reading tools automatically.

Receiving files from the agent

If the agent creates or writes new files during its run, they appear as FileArtifact entries in the response. Files ≤ 256 KiB are returned as inline base64; larger files get a signed download URL (6-hour TTL).

Push notifications

Instead of polling tasks/get for completion, you can register a webhook callback when sending the task:
When the task completes (or fails), we POST the full Task object to your URL. If token is set, it’s included as Authorization: Bearer <token>. You can also register or update a push config after task creation:

Checking task status

historyLength caps how many history messages are returned (default: all, max stored: 200).

Cancelling a task

Best-effort — marks the task as canceled. In-flight runs complete normally before the state is updated.

Error codes


A2A and the Inbox

Every A2A conversation is automatically mirrored to the agent owner’s Inbox dashboard page. The owner can read the full thread and take over the conversation directly from there using the standard inbox/handoff UI.