Guides
Vet a counterparty
Check a stranger's real payment history before you pay them, in one second and for nothing.
The reason to index payments is so that paying a stranger stops being a guess. These are the checks, the queries behind them, and what each answer is actually worth.
All of it is free and takes a second.
The problem, stated precisely#
An agent about to pay another agent has one decision — pay or do not pay — and almost no information. What is available is public and cheap: a wallet address, possibly a registration, possibly a card, and whatever the chain has recorded. What is not available is anything resembling a legal identity, a contract, or recourse.
So the honest framing is not "who is this agent". It is "what is the expected cost of being wrong", and the goal is to make that cost bounded and informed rather than unknown.
Two temptations to resist:
- Treating a registration as a credential. Anyone can register, and anyone can write anything in a card. The only proven fact is that a wallet signed it.
- Treating absence of history as evidence of fraud. Most wallets transacting today have never registered, and every legitimate service was new once.
The one distinction that matters#
A listing is a claim. A settlement is evidence.
A catalog entry costs nothing to create: any price, any description, any name. A distinct payer over time costs real money to manufacture. So when the two disagree, believe the ledger.
Every check below is an application of that.
Check 1 — is anyone paying them?#
curl -sL "https://www.roundhouse.studio/api/v0/merchants/<payTo>" | jqLook at three things, in this order:
| Field | Reading it |
|---|---|
| Distinct payers | The strongest signal. One payer could be the operator; twenty are customers |
| Last settlement | A service last paid in March is not a service |
| Volume | Weakest of the three — one large payer inflates it |
Distinct payers over a period beats total volume every time, because volume is the easiest of the three to manufacture with your own wallets.
Check 2 — is the endpoint alive, and honest about its price?#
curl -sL "https://www.roundhouse.studio/api/v0/endpoints?q=<service>" | jq \
'.endpoints[] | {service_name, resource, price_usdc, pay_to, is_live, http_status, last_indexed_at, l30_unique_payers}'is_live: false— an external probe could not reach it. Do not pay.last_indexed_atmuch older than about forty minutes — probably dropped from the upstream catalog. Stale rows are not yet pruned.price_usdcfar from what has actually been paid — read the live402rather than trusting either.
Check 3 — does the identity hold together?#
Only if they claim one:
curl -sL "https://www.roundhouse.studio/api/v0/agents/<payTo>" \
| jq '.erc8004_agents[] | {chain_id, agent_id, agent_wallet, score}'The check is consistency: does the registry's wallet match the payTo you were quoted? A
mismatch is the interesting case — it may be legitimate (a separate payment address) or it may be
someone else's card attached to their address.
Remember what this proves and does not. A registration proves a wallet signed a document. It does not prove competence, and its absence proves almost nothing — most wallets transacting today have never registered.
Check 4 — what does the reputation say?#
curl -sL "https://www.roundhouse.studio/api/v0/agents/<agentId>/feedback" | jqWeakest of the four, deliberately discounted in the trust score, and worth reading for content rather than for the number — a dispute in the feedback history tells you something an aggregate cannot.
score: null means unknown, not bad.
The queries behind it#
When the endpoints do not cut it, ask directly.
Repeat customers — the single best quality proxy. Anyone can buy once; people come back to things that work.
select count(*) as payers,
count(*) filter (where n > 1) as repeat_payers,
round(100.0 * count(*) filter (where n > 1) / nullif(count(*), 0), 1) as repeat_pct
from (
select payer, count(*) as n
from settlements
where payee = lower('0xTheirWallet')
and block_time > now() - interval '90 days'
group by payer
) tIs the trend up or down?
select day, settlements, usd
from mv_entity_daily
where wallet = lower('0xTheirWallet')
order by day desc
limit 30What are they actually being paid for?
select e.service_name, e.resource, count(*) as calls, count(distinct s.payer) as payers
from settlements s
join external_resources e on e.pay_to = s.payee
where s.payee = lower('0xTheirWallet')
and s.block_time > now() - interval '30 days'
group by 1, 2
order by calls descProven, not merely probable. A settlement with verified_x402 = true carries an on-chain EIP-3009
marker; without the filter you are counting rows that may be ordinary transfers.
select count(*) as all_rows,
count(*) filter (where verified_x402) as proven
from settlements
where payee = lower('0xTheirWallet')
and block_time > now() - interval '90 days'Reading absence#
This is where judgement is needed, so here is the position rather than a rule.
Absence of history means one of: brand new, low volume, paid off-chain, or paid on a chain we do not index. Only the first two are common. None of them is evidence of fraud.
A reasonable response to absence is a bounded first payment rather than a refusal: cap the exposure, transact, and let the record accumulate. Declining every counterparty without history also declines every new entrant, including the legitimate ones.
What is a refusal, regardless of history: a 402 naming a scheme, network or asset your client does
not implement. That is not a risk assessment, it is a capability mismatch.
A policy you can implement#
Not advice about your risk appetite — a shape. The tiers are what a wallet policy can actually enforce.
| Tier | Checks | Cap |
|---|---|---|
| Routine | Endpoint is live; scheme, asset and network recognised | Whatever a call is worth |
| Elevated | Above, plus non-zero distinct payers over 30 days | Bounded per counterparty per day |
| High | Above, plus consistent identity, plus feedback history read | Explicit, per payment |
| Never | Unrecognised asset, network or scheme, whatever else checks out | — |
The summary of the whole page: an identity is necessary but not sufficient, and payment history is strong evidence that new counterparties cannot have yet. Without an identity there is nothing to accumulate reputation against, but an identity alone establishes only that a wallet signed a name. A settlement record is hard to fabricate, which makes it the strongest signal available — and it is one every new entrant starts without. Hence the bounded first payment.
Hand it to an agent#
Vet this counterparty before I pay them. Report each check with the evidence,
then a recommendation.
payTo: <0x…>
Service: <name or URL>
Proposed payment: <$…>
1. GET /api/v0/merchants/<payTo> — distinct payers, last settlement, volume.
2. GET /api/v0/endpoints?q=<service> — is_live, http_status, last_indexed_at,
listed price versus what has actually been paid.
3. GET /api/v0/agents/<payTo> and read erc8004_agents — which registry entries
claim this wallet? If they claimed an agentId, check it is one of them and
that its chain matches. Flag any mismatch.
4. Using POST /api/v0/sql, compute the 90-day repeat-payer percentage and the
proportion of their settlements with verified_x402 = true.
5. Fetch their 402 live and confirm the scheme, network and asset are ones I can
pay.
Recommend one of: proceed, proceed with a cap (say what cap), or refuse — and
name the single check that decided it. Absence of history is a reason for a cap,
not a refusal.Next steps#
- The KYA memo — what a counterparty can sign and commit to
- SQL over the index — more query shapes
- Coverage and confidence — how much we can see