Agent2Agent.
Houston agents speak the Agent2Agent (A2A) protocol, so you can
point any A2A-capable agent, such as LangGraph, CrewAI, or Google's
ADK, straight at a Houston agent and delegate work to it. A2A is
JSON-RPC 2.0 over HTTP, authenticated with your
hst_... API key.
The agent card
Every Houston agent publishes an A2A agent card describing its name, capabilities, and endpoint. Fetch it (authenticated) at:
curl https://poc-gateway.gethouston.ai/a2a/acme/revenue-manager/.well-known/agent-card.json \
-H "Authorization: Bearer hst_9f2c1a7b4e8d0364f1a2b3c4d5e6f7089f2c1a7b4e8d0364f1a2b3c4d5e6f708"
Feed that card URL to your A2A client. :org is your
organization slug and :agent is the agent slug (the
same one the REST API uses).
The JSON-RPC endpoint
All A2A methods are JSON-RPC 2.0 calls to this one endpoint. Houston
supports message/send, message/stream,
tasks/get, and tasks/cancel.
message/send
Send a message to the agent and open a task. The response contains
the task, whose status.state you then poll or stream.
curl -X POST https://poc-gateway.gethouston.ai/a2a/acme/revenue-manager \
-H "Authorization: Bearer hst_9f2c1a7b4e8d0364f1a2b3c4d5e6f7089f2c1a7b4e8d0364f1a2b3c4d5e6f708" \
-H "Content-Type: application/json" \
-d '{
"jsonrpc": "2.0",
"id": "1",
"method": "message/send",
"params": {
"message": {
"role": "user",
"parts": [
{ "kind": "text", "text": "Run a market pulse for Lisbon next weekend." }
]
}
}
}'{
"jsonrpc": "2.0",
"id": "1",
"result": {
"kind": "task",
"id": "task_5f2c1a7b4e",
"contextId": "ctx_8d0364f1a2",
"status": { "state": "working" }
}
}message/stream
Same call, but the response is a Server-Sent Events stream of task and status updates that ends when the task reaches a terminal state. Use this for live progress.
curl -N -X POST https://poc-gateway.gethouston.ai/a2a/acme/revenue-manager \
-H "Authorization: Bearer hst_9f2c1a7b4e8d0364f1a2b3c4d5e6f7089f2c1a7b4e8d0364f1a2b3c4d5e6f708" \
-H "Content-Type: application/json" \
-d '{
"jsonrpc": "2.0",
"id": "1",
"method": "message/stream",
"params": {
"message": {
"role": "user",
"parts": [ { "kind": "text", "text": "Summarize this week for Lisbon." } ]
}
}
}'Multi-turn with taskId
To continue an existing task, for example to answer a follow-up
question the agent asked, send another message with the same
taskId. Houston routes it to the same running mission
instead of starting a new one.
{
"jsonrpc": "2.0",
"id": "2",
"method": "message/send",
"params": {
"taskId": "task_5f2c1a7b4e",
"message": {
"role": "user",
"parts": [ { "kind": "text", "text": "Yes, include Porto too." } ]
}
}
}tasks/get & tasks/cancel
Fetch a task's current state:
{
"jsonrpc": "2.0",
"id": "3",
"method": "tasks/get",
"params": { "id": "task_5f2c1a7b4e" }
}Cancel a running task:
{
"jsonrpc": "2.0",
"id": "4",
"method": "tasks/cancel",
"params": { "id": "task_5f2c1a7b4e" }
}Task states
A2A task states map directly onto Houston mission status:
| A2A task state | Houston mission | Meaning |
|---|---|---|
working | running | The agent is actively working. |
completed | completed | Terminal. The result is attached to the task. |
failed | failed | Terminal. The mission errored. |
canceled | canceled | Terminal. The task was canceled. |
Error codes
Alongside the standard JSON-RPC errors, Houston returns the A2A task errors:
| Code | Name | When |
|---|---|---|
-32001 | TaskNotFound | No task exists for the given id. |
-32002 | TaskNotCancelable | The task already reached a terminal state and cannot be canceled. |
{
"jsonrpc": "2.0",
"id": "4",
"error": { "code": -32002, "message": "Task cannot be canceled" }
}