Skip to content

A2A Protocol

Cerebrus Pulse publishes an A2A Agent Card and answers A2A message/send requests (the A2A protocol, protocol version 0.3), so an A2A agent can find it and ask for a skill in plain language.

Terminal window
curl https://api.cerebruspulse.xyz/.well-known/agent-card.json

The card lists every skill with its price, the payment networks, and the A2A endpoint (https://api.cerebruspulse.xyz/a2a). The same card is served at /.well-known/agent.json and /a2a/.well-known/agent-card.json, and a copy is published at https://cerebruspulse.xyz/.well-known/agent-card.json.

Each skill is served, and priced, by one HTTP endpoint:

Skill IDServed byPrice (USDC)Needs a coinDescription
confluence-analysis GET /pulse/{coin} $0.025 Yes Multi-timeframe technical analysis with the confluence vote share
market-screener GET /screener $0.06 No Screen 50+ perpetuals by signal strength
open-interest-analysis GET /oi/{coin} $0.015 Yes OI deltas, percentile, trend and price-OI divergence
spread-analysis GET /spread/{coin} $0.015 Yes Impact spread and slippage estimates
correlation-matrix GET /correlation $0.05 No BTC-alt correlation matrix with regime
intelligence-bundle GET /bundle/{coin} $0.05 Yes Pulse, 24h funding and sentiment in one call
basis-analysis GET /basis/{coin} $0.02 Yes Perp premium to the Hyperliquid oracle, and oracle vs Chainlink
cex-dex-divergence GET /cex-dex/{token} $0.02 Yes Coinbase vs DEX/Chainlink divergence for one token
collateral-health GET /depeg $0.01 No USDC peg status from Chainlink
liquidation-heatmap GET /liquidations/{coin} $0.03 Yes Modelled liquidation zones with cascade risk
market-stress GET /arb $0.02 No Cross-chain arbitrage stress index

Send a JSON-RPC 2.0 message/send request to the A2A endpoint. This is free: it returns where and how to pay, not data.

import json
import urllib.request
body = json.dumps({
"jsonrpc": "2.0",
"method": "message/send",
"id": "my-task-1",
"params": {
"message": {
"role": "user",
"parts": [{"type": "text", "text": "Analyze BTC confluence"}]
}
}
}).encode()
req = urllib.request.Request(
"https://api.cerebruspulse.xyz/a2a",
data=body,
headers={"Content-Type": "application/json"},
method="POST",
)
with urllib.request.urlopen(req, timeout=15) as resp:
result = json.loads(resp.read())["result"]
quote = result["metadata"]["x402"]
print(result["status"]["state"]) # input-required
print(quote["skill_id"], quote["amount"], quote["currency"])
print(quote["http"]["method"], quote["http"]["url"]) # pay here, with an x402 v2 client

The task comes back in state input-required. Its message says, in words, what the skill costs and which URL to call; result.metadata.x402 says the same in fields:

FieldDescription
statuspayment-required
skill_idThe skill the request was matched to
amountThe price in USDC, e.g. "0.025" (the price of the endpoint that serves the skill)
currencyUSDC
networksThe payment networks, each with network, recipient and label (Base, Solana)
network, recipientThe Base network and recipient, kept for older clients
facilitatorThe x402 facilitator the gateway uses
inBandPaymentfalse: A2A messages cannot carry payment
http.method, http.urlThe request to make: for example GET https://api.cerebruspulse.xyz/pulse/BTC
http.routeThe route that serves the skill, e.g. GET /pulse/:coin
http.paymentHeaderPAYMENT-SIGNATURE: the header an x402 v2 client pays with
paymentRequiredThe x402 v2 terms that endpoint’s 402 carries (absent if the gateway could not build them; the endpoint’s own 402 still has them)

Other outcomes:

  • No coin found for a skill that needs one: state input-required, asking which coin.
  • Service off, payments down, or a stale data feed: state failed, with the reason. Nothing is quoted.

Cerebrus Pulse matches the message to a skill by keywords, or you name the skill in metadata.skill_id.

{
"message": {
"role": "user",
"parts": [{"type": "text", "text": "Show me the top 10 strongest setups"}]
}
}

This maps to market-screener. Without a match, the default is confluence-analysis.

{
"message": {
"role": "user",
"parts": [{"type": "text", "text": "SOL data"}],
"metadata": {"skill_id": "spread-analysis"}
}
}

For skills that need a coin, the symbol is taken from the message text: an upper-case symbol from /coins, or a name such as “ethereum” → ETH or “bitcoin” → BTC.

tasks/get returns a task the server stored. Replies to message/send are complete as sent and are not stored, so there is nothing to poll for; tasks/get on their ids reports “Task not found or expired”.

The A2A endpoint shares the REST limits: 12 requests per minute per IP. See Rate Limits & Errors.