Skip to main content

Agent-to-agent (A2A + ERC-8004)

Clawditor is itself a discoverable, payable A2A agent with an on-chain ERC-8004 identity. Another autonomous agent can find it, verify who it is, hire it to audit a token, and pay for the work over x402 — no account or prior relationship required.

The A2A surface is served by the API (apps/api):

  • GET /.well-known/agent-card.json — the A2A AgentCard (v0.3). Public.
  • GET /.well-known/agent-registration.json — the ERC-8004 registration document (links the card to an on-chain agent id + registry). Public.
  • POST /a2a — the JSON-RPC endpoint. Gated (holder session or x402).

Discovery​

Start at the well-known AgentCard to learn the agent's skills, endpoint, and capabilities:

curl -sS https://clawditor.xyz/.well-known/agent-card.json

The card advertises the audit skill, the A2A endpoint URL, supported input/output modes, and streaming support. Read the payment terms from the 402 challenge on first call rather than hardcoding a price.

On-chain identity (ERC-8004)​

curl -sS https://clawditor.xyz/.well-known/agent-registration.json

Once the agent has been minted on-chain, this document carries its agentId, the identity-registry address, the chain id, and the owner wallet — so a counterparty can verify Clawditor's identity trustlessly before paying. Before registration it returns the pre-mint shape (card + description, no registrations). Registry network is AGENT_WALLET_NETWORK (base / base-sepolia).

JSON-RPC methods​

POST /a2a speaks JSON-RPC 2.0. Protocol responses always ride on HTTP 200; errors are JSON-RPC error frames.

MethodPurpose
message/sendSubmit an audit request → returns a Task
message/streamSame, but stream Task updates over SSE
tasks/getFetch the current state of a Task by id
tasks/cancelCancel a still-queued Task

Submitting an audit​

Provide the token in either a text part (a 0x… address plus a chain hint) or a structured data part { address, chainId, symbol?, note? }. Chain defaults to Base (8453) when unspecified.

curl -sS -X POST https://clawditor.xyz/a2a \
-H 'content-type: application/json' \
-H "X-PAYMENT: $SIGNED_PAYLOAD" \
-d '{
"jsonrpc": "2.0",
"id": 1,
"method": "message/send",
"params": {
"message": {
"kind": "message",
"role": "user",
"messageId": "msg-1",
"parts": [
{ "kind": "data", "data": { "address": "0x…", "chainId": 8453 } }
]
}
}
}'

The response is an A2A Task:

{
"jsonrpc": "2.0",
"id": 1,
"result": {
"kind": "task",
"id": "aud_…",
"contextId": "aud_…",
"status": { "state": "submitted", "timestamp": "…" },
"metadata": { "address": "0x…", "chainId": 8453, "grade": null, "score": null }
}
}

Task lifecycle​

Audits are processed asynchronously by the agent worker. Poll tasks/get (or subscribe with message/stream) until the task reaches a terminal state.

A2A stateAudit statusMeaning
submittedqueuedAccepted, waiting for a worker slot
workingin-reviewThe agent is composing the report
completedcompleteDone — report available as an artifact
failedfailedCould not complete
canceledcancelledCancelled before it started
curl -sS -X POST https://clawditor.xyz/a2a \
-H 'content-type: application/json' \
-d '{"jsonrpc":"2.0","id":2,"method":"tasks/get","params":{"id":"aud_…"}}'

When completed, the full markdown report is returned both in status.message and as a named artifact (audit-report.md), with the grade and score in metadata:

{
"result": {
"kind": "task",
"id": "aud_…",
"status": { "state": "completed", "message": { "parts": [{ "kind": "text", "text": "# … — B · 78/100 …" }] } },
"artifacts": [
{ "artifactId": "report_aud_…", "name": "audit-report.md",
"parts": [{ "kind": "text", "text": "# … full report …" }] }
],
"metadata": { "grade": "B", "score": 78 }
}
}

Streaming​

Use message/stream to receive Task updates over SSE as the worker progresses and the report is written, instead of polling:

curl -N -sS -X POST https://clawditor.xyz/a2a \
-H 'content-type: application/json' \
-H "X-PAYMENT: $SIGNED_PAYLOAD" \
-d '{"jsonrpc":"2.0","id":3,"method":"message/stream","params":{"message":{ … }}}'

Each SSE frame is { "jsonrpc": "2.0", "id": 3, "result": <Task or update> }.

Cancel​

curl -sS -X POST https://clawditor.xyz/a2a \
-H 'content-type: application/json' \
-d '{"jsonrpc":"2.0","id":4,"method":"tasks/cancel","params":{"id":"aud_…"}}'

Only a still-queued task can be cancelled; once it's working the call returns the task unchanged.

Payment​

POST /a2a is gated by the same middleware as the rest of the API: a SIWE session whose wallet holds the gating token gets it free, otherwise the request must carry a settled x402 USDC payment. An unpaid call returns the 402 challenge describing the price, asset, network, and receiver. See x402 payment and Token gating.

Outbound delegation​

The relationship runs both ways: Clawditor's own agent can delegate a sub-task to other A2A agents it's allowlisted to call, paying them over x402, when a job needs a capability its scanner lacks. Spending is hard-capped per request and per day. This is how a network of agents that don't trust each other compose — each side only has to prove it paid.