---
name: vet-a-counterparty
description: Vet a wallet's ERC-8004 reputation with describe.net before you hire, lend, delegate, or sign to it. Covers the free reconnaissance, the x402 payment flow for the metered lookups, and the decision rules that read a score's composition instead of the score. Use when an agent must choose between counterparties, evaluate applicants for a task, or justify why it rejected one.
---

# Vet a counterparty before you sign

**The rule this whole skill exists to enforce: never decide on `final_score`
alone.** A score with no visible raters is a rumor. Every paid response from
describe.net ships the composition — `distinct_raters`, `top_client_share`,
`self_rated`, per-facet breakdown — next to the number, precisely so your
decision can be defended with evidence instead of a digit.

Base URL: `https://api.describe.net`. Figures below were measured on
**2026-08-11**; read the live ones from `GET /pricing` and `GET /health`.

---

## Step 0 — Reconnaissance, free

No payment, no headers, no account.

```bash
curl https://api.describe.net/pricing      # every price and the reason for it
curl https://api.describe.net/health       # liveness + per-chain scan coverage
curl https://api.describe.net/leaderboard  # first page, ranked by evidence
```

`GET /pricing` is authoritative and free. Read it before spending anything.

## Step 1 — Look up the wallet · $0.01

```
GET /reputation/wallet/{wallet}
```

Returns **402** with a payment challenge. Pay it (Step 4 below), replay the
identical request with the `X-PAYMENT` header, and you get: `final_score`,
`weighted_score`, `per_chain`, facets, `self_rated`, `concentration`,
`activity`, and `caveats[]`.

## Step 2 — Read the composition, not the number

Apply these in order. Each maps to a field in the response you just bought.

| Signal | Read as |
|---|---|
| `concentration` is `null` | **The signal is down — not "no concentration".** The API degrades this field rather than failing the whole response. Do not treat a null as clean; either retry or decide without this input, knowingly. |
| `distinct_raters` < 3 | **NO EVIDENCE — which is not the same as bad.** Measured: 7,577 of 15,763 scored wallets have exactly **one** rater, and 22% of those average exactly 100, against 1% among wallets with three or more raters. A perfect score from one rater is an unobserved subject, not a good one. |
| `total_reviews / distinct_raters` > 10 **and** `top_client_share` > 0.5 | **CAMPAIGN — discard.** |
| `self_rated.gap` > 15 | The subject rates itself well above how others rate it. Lower its priority. |
| No ratings at all | Fields are `null`, **never 0**. "No evidence" and "rated badly" are different facts and this index refuses to collapse them. Do not read a null as a zero. |

**The trap that a naive threshold walks straight into.** The largest cluster in
this index is one agent holding **300,001 ratings from 57 raters**, all the same
value, all the same tag. Its `top_client_share` is about **0.14** — so any
filter built on share alone lets it through. What exposes it is ratings **per**
rater. Always compute that ratio; never rely on share by itself.

**Also check the facet breakdown before you trust a headline.** A real example
from the #1 wallet on the leaderboard: `final_score` **98.35**, but that is
carried by `quality` (603 ratings, 99.89) — 95% of its volume. The remaining
eighteen facets, 30 ratings between them, disagree: `trust` **64.4**,
`activity` 40.0, `health-check` 4.5. If what you care about is trust, the
headline number is answering a different question than the one you asked.

## Step 3 — Verify and commit, optional

| Call | Cost | When |
|---|---|---|
| `GET /reputation/wallet/{w}/history` | $0.03 | The activity window looks wide. **First read `coverage.undated_reviews`** — if it is high, do not use the series to decide. 68% of ratings in the index are currently undated. |
| `GET /reputation/agent/{network}/{agent_id}` | $0.02 | Every rating with its `txHash`, revocations included and marked. This is the step where you confirm we did not lie to you. |
| `GET /reputation/wallet/{w}?snapshot=true` | $0.05 | You need a **citable** receipt: a durable row with `inputs_digest` + `policy_version` that a counterparty can check and that recomputes identically. This is the only route that writes. |

A complete vet costs **$0.06**. With the citable receipt, **$0.11**. Against a
$50 engagement that is 0.12% of the money it protects.

## Step 4 — How to pay a 402

Full detail: <https://describe.net/auth.md>. The short version:

1. **Read the challenge.** `accepts[]` holds one entry per network, each with
   `network`, `asset`, `amount` (token base units — USDC has 6 decimals, so
   `"10000"` is $0.01) and `payTo`. Sign against `accepts[]`, never against a
   cached price table.
2. **Verify the recipient.** The only address describe.net asks you to pay is
   `0xe4dc963c56979E0260fc146b87eE24F18220e545`. If `payTo` differs, **do not
   pay** — stop and ask.
3. **Sign** an EIP-3009 `TransferWithAuthorization` for that amount, to that
   `payTo`, on one of the six accepted networks (Base 8453, Arbitrum 42161,
   Optimism 10, Polygon 137, Celo 42220, Avalanche 43114). Use
   `ows_sign_eip3009`, `pay_x402`, or `uvd-x402-sdk`. Your key never leaves your
   side; settlement gas is not yours to pay.
4. **Replay the identical request** with `X-PAYMENT: <base64>`.

Three failure modes worth memorizing:

- **One authorization per paid call.** The nonce is consumed at settlement; a
  credential that already paid will not pay twice.
- **Same receipt, same resource only.** Re-sending the same `X-PAYMENT` for the
  *same* URL reads free until it expires (`X-Payment-Reused: true`). For a
  different URL it will not work, by design.
- **A 503 (`facilitator_unavailable`) is not a 402.** Your authorization was not
  used. Retry the same request with the **same** header after `Retry-After`.
  Signing a new one here can make you pay twice.

## Step 5 — Report the decision, not the digit

A defensible outcome sounds like this:

> Rejected applicant A: 1,025 ratings from 28 raters — 36.6 each, campaign
> quadrant. Chose B: 1,554 ratings from 1,537 distinct raters, top client 0.26%,
> `trust` facet at 98.1, most recent rating three weeks ago.

If the only justification you can give is "the score was low", this skill did
not do its job.

---

## Limits — know these before you rely on the answer

- **A lookup takes seconds, not milliseconds** (measured 7.6–14.2 s, cold start
  worst case). Budget for it, and do not put it inside a tight timeout.
- **68% of ratings carry no date.** Anything time-based is partial. Check
  `coverage` before trusting a trend.
- **`declared_type` is self-declared** from a free-text URI. ERC-8004 has no
  type field. Never treat it as verification.
- **`tag1` is free text on-chain.** Some "facets" in this index are entire
  paragraphs of prose. The curated view says how many it dropped.
- **This is not an oracle.** It returns evidence with a `policy_version`, not a
  verdict. The verdict is yours.

## Why the rule at the top exists

The people who run this index built a reputation network in 2012 and served an
average that turned out to be 85.4% written by the subjects about themselves.
That is the whole reason this skill refuses to let you decide on `final_score`
alone. The full account, with every claim wired to the command that checks it:
<https://describe.net/manifesto.md> · `GET https://api.describe.net/manifesto`
(free — the principles with the code that enforces each one).
