Docs
Check any Celo address before paying it, from a browser, an HTTP call, an x402 client or an MCP tool. Read the score onchain from a contract.
Quickstart
The free endpoint returns the whole report for any address. No key, no wallet.
curl https://api.assayscore.xyz/v1/address/0xSELLERAgents that check sellers before paying them use the paid check: $0.002 over x402 in USD₮ by default, or USDC, USA₮, wARS, wBRL or wCOP. No rate limit, and a signed score in the answer.
import { x402Client, wrapFetchWithPayment } from "@x402/fetch";
import { ExactEvmScheme } from "@x402/evm/exact/client";
import { privateKeyToAccount } from "viem/accounts";
import { preferAssets } from "assayscore";
// Pay in the token your wallet holds; x402 otherwise takes the server's first option (USD₮).
const client = new x402Client(preferAssets("USDT", "USDC"))
.register("eip155:42220", new ExactEvmScheme(privateKeyToAccount(KEY)));
const pay = wrapFetchWithPayment(fetch, client);
const res = await pay("https://api.assayscore.xyz/v1/check/0xSELLER");
const { verdict, rating, reasons, attestation } = await res.json();HTTP API
| Endpoint | Price | Returns |
|---|---|---|
GET /v1/check/:address | $0.002 | pass, caution or block; rating; organic share; reasons; signed EIP-712 score |
GET /v1/attest/:address | $0.01 | the full report plus a signed score AssayRegistry accepts |
GET /v1/address/:address | free, rate limited | the full report: revenue split, payers, flags with evidence, identity |
GET /v1/economy | free | gross vs organic volume, loops, ratings, review stats, top sellers |
GET /v1/economy/daily?days=120 | free | volume per UTC day, gross and organic |
GET /v1/sellers?sort=organic|gross | free | every seller with its rating, paginated |
GET /v1/agents?q=&paid=1 | free | ERC-8004 agents ranked by reviews from paying wallets |
GET /v1/agents/:id | free | one agent with its report and every review, each tiered by payment |
GET /v1/agents/:id/payments/:client | free | a client's settlements to an agent, for reviewing |
GET /v1/proof/:tx | free | a live check of one settlement transaction on Celo |
GET /v1/status | free | indexed block, lag, relayers, attester and registry |
GET /.well-known/agent-registration.json | free | Assay's own ERC-8004 registration file |
Errors are JSON with error and message. Bad addresses answer 400 before any payment is asked for. The free endpoints allow 60 calls a minute per IP and answer 429 with retry-after after that.
SDK guard
withAssayGuard wraps any x402 paying fetch. When a seller answers 402, every payTo it offers is checked first; a blocked seller throws AssayBlockedError and nothing is paid. Responses that are not 402 pass through untouched.
import { withAssayGuard, AssayBlockedError } from "assayscore";
// npm install assayscore
const guarded = withAssayGuard(fetch, pay, {
minRating: "BB", // optional: refuse anything rated below BB
allowUnrated: true, // new sellers have to start somewhere
onAssayError: "allow", // fail open if Assay is unreachable; "block" to fail closed
});
try {
await guarded("https://seller.example/api/forecast");
} catch (e) {
if (e instanceof AssayBlockedError) console.log(e.result.reasons);
}MCP server
Read-only tools for any MCP client: assay_check_seller (with fresh_x to buy an X search on the spot when the client can pay), assay_report, assay_independent_payers, assay_find_agents and assay_economy.
claude mcp add assay -- npx -y assayscore-mcp
# Claude Desktop, Cursor or any MCP client:
# { "mcpServers": { "assay": { "command": "npx", "args": ["-y", "assayscore-mcp"] } } }AssayRegistry
A paid check or report includes an EIP-712 Score signed by Assay’s attester. Anyone can submit it to AssayRegistry on Celo; contracts then read it without trusting an API. Scores are valid for 7 days and only a newer score replaces an older one.
interface IAssayRegistry {
function isInvestmentGrade(address subject) external view returns (bool); // fresh and BBB or better
function verify(Score calldata s, bytes calldata signature) external view returns (bool);
}
function payOut(address seller) external {
require(assay.isInvestmentGrade(seller), "seller not investment grade");
// ...
}Rating codes run from 1 (D) to 8 (AAA); 0 is not rated. The domain is Assay, version 1, chain 42220, verifying contract the registry.
Payment-verified reviews
Reviews in the ERC-8004 Reputation Registry cost nothing to write, so most say little. Assay tiers every review on Celo: payment proven when its feedback file names a settlement that Assay finds onchain from the reviewer to the agent, paid customer when the reviewer paid the agent before writing it, and never paid it otherwise. Reviews written from an agent’s page here store their file inline as a data: URI with proofOfPayment, so anyone can check them without Assay.
Methodology
Version 2026.10-1. Every x402 settlement on Celo is read from finalized blocks:
- EIP-3009 transfers of USDC, USD₮ and USA₮ that the payer signed and someone else submitted, paired with their
AuthorizationUsedevent; - wARS, wBRL and wCOP transfers inside calls to the x402 Permit2 proxy, priced in dollars at that day’s rate.
Revenue is then assayed. A payment counts as organic unless:
- It comes back. Sellers and payers that can reach each other through payments form a loop (a strongly connected component). Within a loop only the net inflow counts: money the seller sends back to its loop is subtracted from what the loop paid it.
- The seller paid for it. A payer first funded by the seller, or by a wallet the seller funded, counts for nothing.
- It shares the seller’s purse. A payer funded by the seller’s own private funder, or by a member of its loop, counts for nothing. Exchanges, bridges, contracts and very busy wallets are public sources and are ignored, unless they buy or sell over x402 themselves.
The score is 100 × quality^1.5 × (0.55 × diversity + 0.45 × track) × dormancy + identity, where quality is the organic share, diversity is 1 − e^(−payers/6) over effective independent payers (an inverse Herfindahl in which wallets with one private funder, or one Self human, count once and wallets created only to pay count half), track is 1 − e^(−days/10) over days with organic revenue, dormancy is 0.85 after 30 idle days and 0.6 after 90, and identity adds up to 8 points for an ERC-8004 identity and a fresh Self proof, only when quality is 0.5 or more.
| AAA | AA | A | BBB | BB | B | CCC | D |
|---|---|---|---|---|---|---|---|
| 90+ | 80+ | 70+ | 60+ | 45+ | 30+ | 15+ | 0+ |
Fewer than 5 settlements, 2 payers or $0.05 of revenue is a thin file: the numbers are shown and the rating is NR. Funding data is filled in continuously; until a payer is checked it is treated as independent and the report says how much is checked. wFIAT days before Assay’s first stored rate use the earliest stored rate.
Alerts
Watch an address and get a signed webhook when something changes: the rating, the pre-payment verdict, a new critical finding, or posts with warning words naming it on X. One payment of $0.05 over x402 covers thirty days; paying again for the same address and URL extends it.
POST https://api.assayscore.xyz/v1/watch # x402, $0.05
{ "address": "0xSeller…", "url": "https://your.app/assay-webhook" }
# 201 → { "id": "w_…", "secret": "…", "expiresAt": 1764000000 }
# The first delivery, watch.started, arrives within two minutes.Every delivery is a JSON POST with x-assay-event, x-assay-timestamp and x-assay-signature: sha256=HMAC(secret, timestamp + "." + body). Check the signature, then read event, detail, previous and current. A delivery that fails is retried for up to half a day; URLs must be public https, and redirects are not followed. GET /v1/watch/:id and DELETE /v1/watch/:id take the secret in x-assay-watch-secret.
Claim your page
If a seller address is yours, open its report and use “Claim this page”: connect that wallet, sign one message (it moves no money), and your name, what you sell, website and X handle appear on the report and in the sellers directory. A claim says “this wallet’s owner chose this name”; names that read as someone else’s are refused. Every address also has a badge for READMEs that shows its current rating and links to the report.
[](https://assayscore.xyz/address/0xYourAddress)Find sellers
The sellers directory lists every x402 seller on Celo, ranked by organic revenue, searchable by name, what they sell, category or address, with a rating floor and a claimed-only switch. Agents get the same list from GET /v1/sellers?q=&minRating=&category=&claimed=1 and the MCP tool assay_find_sellers, so a buyer’s agent can pick a reliable seller instead of only checking one it already found.
Raise your rating
Every report with revenue carries “What would raise this rating”: how many more independent customers reach the next rating, what time and activity add, and what identity is worth, each computed by running the real score formula on the changed input. It cannot be gamed: payers you funded or that share your funder are struck out before anything is scored, so the only lever that moves a rating is real customers. Also at GET /v1/address/:address/plan and the MCP tool assay_rating_plan.
Right of reply
A credit bureau lets you dispute. On your own report, connect the wallet and answer any finding in your own words: the response appears under that finding, dated and marked as yours. It never changes the score; the finding stays and readers weigh both. Owners of claimed pages also get free alerts on their own address, ninety days per signature (POST /v1/respond, POST /v1/watch/own).
Check a payer
The mirror of the pre-payment check, for sellers. Before a refund, an allowance or credit, paste a payer’s address on your report: established customer, new wallet, caution or block, with the reasons in plain words (age on Celo, who funded it, how many sellers it pays, loop share, identity, and how it stands to you). Also at GET /v1/payer/:address?seller=0x… and the MCP tool assay_check_payer.
Independent payers
The Agents on Open Rails hackathon counts a payer only if it is not yours, was not first funded by you or your own funder, and was active on Celo before the window started. Assay already traces all three, so any team can see how its payers come out under that rule, free, with each payer’s volume inside the window: on every report, and at GET /v1/independent/:address.
Pricing and limits
Reports in the browser and the free endpoints cost nothing, within 60 calls a minute. Paid endpoints are $0.002 per check, $0.01 per check with an X search bought now for you (/v1/check/:address/x), $0.01 per full report with attestation, and $0.05 for thirty days of alerts on one address, paid over x402 through Celo’s facilitator in USD₮ by default, or USDC, USA₮, or Ripio’s wARS, wBRL and wCOP at the day’s exchange rate. Nobody needs CELO for gas, wFIAT included. The seller pays the facilitator’s fee; buyers pay only the price.
For a payment under a cent, the free report is the right tool: the paid check exists for the signature a contract can verify and for evidence fetched on demand. If a paid search cannot be bought or does not answer, the API answers 502 or 503 and the x402 payment is not settled.
Run your own
Assay is open source. One process indexes Celo, enriches addresses and serves the API from a SQLite file; the web app is a separate Next.js deploy.
git clone https://github.com/Oshioke-Salaki/assay && cd assay
pnpm install && pnpm build
cp apps/server/.env.example apps/server/.env # set PAY_TO, X402_API_KEY, ATTESTER_PRIVATE_KEY, REGISTRY_ADDRESS
pnpm --filter @assay/server backfill # index Celo history once
pnpm --filter @assay/server start # API + indexer