API Reference

Complete reference for the A2A protocol implementation: architecture, methods, types, scopes, security, and the ohwow-connect relay.

Note

This section is for developers integrating with the A2A protocol. Looking for the user guide? Start with the Welcome page.

How It Works#

ohwow operates in two modes simultaneously. As a server, it accepts incoming A2A requests from external agents. As a client, it makes outbound requests to external A2A agents.

System architecture
┌─────────────────────────────────────────────────────────┐
│                     ohwow Platform                      │
│                                                         │
│  ┌──────────────┐    ┌──────────────┐   ┌────────────┐  │
│  │  A2A Server  │    │  Agent Core  │   │ A2A Client │  │
│  │              │───▶│              │──▶│            │  │
│  │  /api/a2a    │    │  Execution   │   │  Outbound  │  │
│  │  Agent Card  │    │  Engine      │   │  Requests  │  │
│  └──────┬───────┘    └──────────────┘   └─────┬──────┘  │
│         │                                     │         │
│    Auth │ Scopes                         Discovery      │
│    Rate │ Limit                          & Tasks        │
│         │                                     │         │
└─────────┼─────────────────────────────────────┼─────────┘
          │                                     │
          ▼                                     ▼
   ┌──────────────┐                    ┌──────────────┐
   │   External   │                    │   External   │
   │   Agents     │                    │   A2A Agents │
   │  (inbound)   │                    │  (outbound)  │
   └──────────────┘                    └──────────────┘

Inbound Request Flow#

When an external agent calls your ohwow instance, the request flows through several layers:

Inbound request flow
External Agent
      │
      ▼
  ┌─────────┐    ┌─────────┐    ┌──────────┐    ┌──────────┐
  │  Auth    │───▶│  Scope  │───▶│   Rate   │───▶│  Agent   │
  │  Check   │    │  Check  │    │  Limit   │    │  Execute │
  │          │    │         │    │          │    │          │
  │ Bearer   │    │ Verify  │    │ Sliding  │    │ Run the  │
  │ Token    │    │ scopes  │    │ window   │    │ task     │
  └─────────┘    └─────────┘    └──────────┘    └────┬─────┘
                                                     │
                                                     ▼
                                              ┌──────────┐
                                              │ Sanitize │
                                              │ Response │
                                              │          │
                                              │ Strip    │
                                              │ metadata │
                                              └──────────┘
  1. Authentication: Bearer token with ohw_a2a_ prefix is validated against hashed keys in the database.
  2. Scope check: The requested method is checked against the key's allowed scopes. For example, tasks.create is required for tasks/send.
  3. Rate limiting: Sliding window rate limiter enforces per-minute and per-hour limits per API key.
  4. Execution: The matched agent processes the task using the standard execution engine.
  5. Sanitization: Internal metadata (workspace IDs, costs, model config) is stripped before the response is returned.

Outbound Request Flow#

When your agents need to call external A2A agents, the outbound flow handles discovery, authentication, and result storage:

Outbound request flow
Your ohwow Agent
      │
      ▼
  ┌──────────┐    ┌──────────┐    ┌──────────┐    ┌──────────┐
  │ Discover │───▶│  Auth    │───▶│   Send   │───▶│  Store   │
  │          │    │          │    │   Task   │    │  Result  │
  │ Fetch    │    │ Use the  │    │          │    │          │
  │ Agent    │    │ saved    │    │ JSON-RPC │    │ Summary  │
  │ Card     │    │ creds    │    │ request  │    │ only     │
  └──────────┘    └──────────┘    └──────────┘    └──────────┘
  1. Discovery: Fetch and cache the remote agent's Agent Card to understand its capabilities.
  2. Authentication: Use the credentials configured in the connection (API key, OAuth, bearer token, or mTLS).
  3. Task send: Dispatch the JSON-RPC request and wait for the result.
  4. Result storage: By default, only a summary (max 500 characters) is stored. Raw results are not persisted unless store_results is enabled.

Agent Card Schema#

The Agent Card is published at /.well-known/agent.jsonand describes your agents' capabilities.

A2AAgentCard
interface A2AAgentCard {
  name: string;              // Display name
  description: string;       // What this agent system does
  url: string;               // A2A endpoint URL
  version: string;           // Protocol version (e.g. "0.3")
  capabilities: {
    streaming: boolean;             // Supports SSE streaming
    pushNotifications: boolean;     // Supports push notifications
    stateTransitionHistory: boolean; // Returns task history
  };
  authentication: {
    schemes: string[];       // e.g. ["bearer"]
    credentials?: string;    // How to get credentials
  };
  defaultInputModes: string[];  // e.g. ["text"]
  defaultOutputModes: string[]; // e.g. ["text"]
  skills: A2ASkill[];          // List of agent capabilities
}

Skill Schema#

A2ASkill
interface A2ASkill {
  id: string;           // Unique identifier (e.g. "content-writing")
  name: string;         // Human-readable name
  description: string;  // What this skill does
  tags?: string[];      // Searchable tags
  examples?: string[];  // Example prompts
  inputModes?: string[];  // Override default input modes
  outputModes?: string[]; // Override default output modes
}

Authentication#

All A2A requests require a Bearer token in the Authorization header. Keys use the ohw_a2a_ prefix.

http
POST /api/a2a HTTP/1.1
Content-Type: application/json
Authorization: Bearer ohw_a2a_your_key_here

JSON-RPC Methods#

All requests use JSON-RPC 2.0 format. The endpoint is /api/a2a.

MethodRequired ScopeDescription
tasks/sendtasks.createSend a message to create or continue a task
tasks/sendSubscribetasks.streamSend a message with SSE streaming response
tasks/gettasks.readGet the current status and result of a task
tasks/canceltasks.cancelCancel a running task
tasks/pushNotification/settasks.createRegister a webhook for task updates
tasks/pushNotification/gettasks.readGet push notification config for a task

tasks/send#

Request
{
  "jsonrpc": "2.0",
  "id": "1",
  "method": "tasks/send",
  "params": {
    "message": {
      "role": "user",
      "parts": [
        { "type": "text", "text": "Your task description here" }
      ]
    },
    "sessionId": "optional-session-id"
  }
}
Response
{
  "jsonrpc": "2.0",
  "id": "1",
  "result": {
    "id": "task_abc123",
    "status": {
      "state": "completed",
      "message": {
        "role": "agent",
        "parts": [{ "type": "text", "text": "Here are the results..." }]
      }
    },
    "artifacts": []
  }
}

tasks/get#

Request
{
  "jsonrpc": "2.0",
  "id": "2",
  "method": "tasks/get",
  "params": {
    "id": "task_abc123",
    "historyLength": 10
  }
}

Scopes#

Each API key has a set of scopes that determine what operations it can perform.

ScopeDescription
tasks.readRead task status and results
tasks.createCreate new tasks via tasks/send
tasks.cancelCancel running tasks
tasks.streamUse streaming (SSE) responses
agents.readRead individual agent details
agents.listList available agents
results.readRead task result data
results.filesAccess file artifacts from results

Trust & Security#

Trust Levels#

Every A2A API key and connection is assigned a trust level that controls what actions are allowed. Higher levels include all permissions from lower levels.

LevelWhat It AllowsBest For
read_onlyList agents, read task status, read resultsDashboards, monitoring, analytics
executeEverything above + create new tasksPartner integrations, limited automation
autonomousEverything above + cancel tasks, access file artifactsFull automation, CI/CD pipelines
adminAll scopes including streamingInternal tools only (not for external use)

Warning

Only use the admin trust level for internal, trusted tools. Never assign admin to external connections.

PII Redaction#

Before any response leaves ohwow via the A2A protocol, the sanitizer automatically strips internal metadata that should never be exposed to external agents:

  • workspace_id
  • user_id
  • internal_task_id
  • system_prompt
  • cost_breakdown
  • model_config
  • browser_session_id
  • memory_document
  • api_key_id

This happens at the protocol layer, so agents and task handlers don't need to worry about accidentally leaking internal data.

Summaries-Only Mode#

For outbound A2A connections, ohwow stores only a summary of each result by default, not the raw data. Summaries are capped at 500 characters.

This means even if the external agent returns large payloads, only a concise human-readable summary is persisted in your workspace. You can enable full result storage per connection by setting store_results: true.

Data Sovereignty#

You have full control over what data leaves your workspace via A2A:

  • Outbound connections: Each connection has configurable allowed_data_types that restrict what categories of data can be sent.
  • Result retention: Set result_retention_hours per connection. After this window, stored results are deleted.
  • Agent-level permissions: Control which of your agents an external key or connection can access.

Rate Limiting#

Every A2A API key has two rate limits enforced via a sliding window:

  • Per-minute limit: Prevents burst abuse. Default: 60 requests/minute.
  • Per-hour limit: Prevents sustained abuse. Default: 1,000 requests/hour.

When rate limited, the API returns error code -32004 (RATE_LIMITED). Callers should implement exponential backoff.

Key Rotation#

To rotate an API key:

  1. Create a new key with the same scopes in your dashboard settings.
  2. Update your external systems to use the new key.
  3. Revoke the old key. Revoked keys are immediately rejected with no grace period.

Tip

Keys also support expiration dates. Set expires_at when creating a key for automatic rotation.

Error Codes#

CodeNameDescription
-32700PARSE_ERRORInvalid JSON in request body
-32600INVALID_REQUESTMissing required JSON-RPC fields
-32601METHOD_NOT_FOUNDUnknown method name
-32602INVALID_PARAMSMissing or invalid parameters
-32603INTERNAL_ERRORServer-side error during execution
-32001TASK_NOT_FOUNDNo task with the given ID
-32002TASK_NOT_CANCELABLETask is already completed or failed
-32003UNAUTHORIZEDInvalid or missing API key
-32004RATE_LIMITEDToo many requests; try again later
-32005AGENT_NOT_FOUNDNo agent matches the request
-32006SCOPE_INSUFFICIENTAPI key lacks the required scope

Key Types#

Task#

typescript
interface A2ATask {
  id: string;
  sessionId?: string;
  status: {
    state: 'submitted' | 'working' | 'input-required'
         | 'completed' | 'canceled' | 'failed';
    message?: A2AMessage;
    timestamp?: string;
  };
  artifacts?: A2AArtifact[];
  history?: A2AMessage[];
  metadata?: Record<string, unknown>;
}

Message & Parts#

typescript
interface A2AMessage {
  role: 'user' | 'agent';
  parts: A2APart[];
  metadata?: Record<string, unknown>;
}

type A2APart = A2ATextPart | A2AFilePart | A2ADataPart;

interface A2ATextPart {
  type: 'text';
  text: string;
}

interface A2AFilePart {
  type: 'file';
  file: {
    name?: string;
    mimeType?: string;
    bytes?: string;  // base64
    uri?: string;
  };
}

interface A2ADataPart {
  type: 'data';
  data: Record<string, unknown>;
}

Artifact#

typescript
interface A2AArtifact {
  name?: string;
  description?: string;
  parts: A2APart[];
  index: number;
  append?: boolean;
  lastChunk?: boolean;
}

Note

All type definitions are available in the source at src/lib/a2a/types.ts.

ohwow-connect Relay#

What Is It?#

ohwow-connect is a lightweight relay that runs on your machine or private network. It creates a secure tunnel to the ohwow platform, allowing your locally-running agents to receive and respond to A2A tasks without exposing them to the public internet.

This is ideal for agents that access internal databases, run on private infrastructure, or need to stay behind a firewall.

Docker Setup#

The fastest way to get started:

Docker
docker run -d \
  --name ohwow-connect \
  -e OHWOW_API_KEY=ohw_a2a_your_key_here \
  -e OHWOW_WORKSPACE_ID=your_workspace_id \
  -e LOCAL_AGENT_URL=http://host.docker.internal:3001 \
  -p 9090:9090 \
  ghcr.io/ohwow/connect:latest

The relay exposes a local admin UI at http://localhost:9090 where you can monitor connection status and task logs.

npm Setup#

If you prefer running it directly with Node.js:

npm
npx ohwow-connect init

This creates an ohwow-connect.yaml config file. Edit it, then start the relay:

bash
npx ohwow-connect start

Configuration#

The config file defines your workspace, agents, and routing:

ohwow-connect.yaml
# ohwow-connect configuration
workspace_id: "your_workspace_id"
api_key: "ohw_a2a_your_key_here"

# Local agents to expose via A2A
agents:
  - name: "Internal Analytics"
    description: "Runs queries against our private data warehouse"
    local_url: "http://localhost:3001/api/agent"
    skills:
      - id: "sql-query"
        name: "SQL Query"
        description: "Execute read-only SQL queries"
      - id: "report-gen"
        name: "Report Generation"
        description: "Generate formatted reports from query results"

  - name: "Document Processor"
    description: "Processes internal documents and contracts"
    local_url: "http://localhost:3002/api/agent"
    skills:
      - id: "doc-summarize"
        name: "Summarize Document"
        description: "Extract key points from a document"

# Optional settings
health_check_interval: 30  # seconds
retry_attempts: 3
log_level: "info"

Register in Dashboard#

After starting the relay, register your local agents in the ohwow dashboard:

  1. Go to Dashboard Settings → Connections.
  2. Click "Add Connection" and select "ohwow-connect Relay".
  3. Enter your workspace ID and the relay will auto-discover your local agents.
  4. Set trust level and permissions for each agent.

Troubleshooting#

IssueSolution
Relay can't connect to ohwowCheck your API key and workspace ID. Ensure outbound HTTPS is allowed.
Local agent not respondingVerify the local_url is reachable from the relay container. Use host.docker.internal for Docker.
Tasks timing outIncrease timeout in config. Check that your local agent responds within 30 seconds.
Connection drops frequentlyCheck network stability. The relay auto-reconnects with exponential backoff.
Agent not appearing in dashboardClick "Refresh" in the connections panel. The relay sends agent cards on startup.
"UNAUTHORIZED" errorsYour API key may be revoked or expired. Create a new key in Dashboard Settings.

Tip

For detailed logs, set log_level: "debug" in your config file or pass -e LOG_LEVEL=debug to Docker.