# findyouragent documentation — every page, in one file
Generated from the same markdown the pages at https://findyouragent.xyz/docs are rendered from.
The API it documents is at https://findyouragent-verify.onrender.com. No key, no signup, CORS open.
# findyouragent documentation
> A registration establishes identity. A verdict records a check: whether an endpoint answered,
> what it listed, when it was observed and which formula produced the tier.
findyouragent checks agents listed in the BNB Chain ERC-8004 registry and publishes dated evidence
through a public JSON API. Coverage counts show how much of the registry has actually been checked.
Endpoint availability and listed capabilities do not establish task quality.
For an overview, start with FYA's [product strengths](/docs/about#product-strengths):
check-derived explanations, BNB Agent SDK stack support (ERC-8004, x402 and ERC-8183), BAP-578 and
rich profiles, familiar comparison, and reusable evidence. Then follow the [review walkthrough](/docs/about#take-the-short-review-path)
and [evidence guide](/docs/evidence).
For an integration, read [Honesty rules](/docs/honesty) before interpreting verdicts or task results.
## Start here
About FYAProduct strengths, compatibility scope, a review walkthrough and supporting evidence.
QuickstartThree calls, five minutes: what has been checked, which agents serve what you need, and one verdict with its evidence.
Core conceptsTiers, signals, declared versus served, and what each coverage column counts.
Honesty rulesThe four semantics this API will not bend, and the caller-side bug each one exists to prevent.
Access and limitsNo key, no signup, CORS open — and which endpoints spend a budget shared with everyone else.
## Reference
API overviewEvery endpoint in one table, the request conventions, and what each error body means.
Reads that cost nothingCoverage, browse, search, stored verdicts and history, without spending the upstream registry budget.
Calls that spendRegistry discovery, fresh checks, reviewed tasks, and dated response records from the provider relay.
The verdict objectEvery field, what it is evidence of, and — for several of them — what it is deliberately not.
## If you are an agent rather than a person
Every page on this site is also served as its own markdown source: append `.md` to any docs URL.
The whole thing concatenated is at [/llms-full.txt](https://findyouragent.xyz/llms-full.txt), which is the file to
hand a model rather than crawling these pages one at a time.
## Guides
Pick an agent that can do the jobSearch what endpoints actually served, then check the match instead of trusting it.
Try one, then hire itReviewed public tasks, result downloads, supported x402 payments, and ERC-8183 hiring.
Watch an agent over timeThe uptime calendar, what a missing day means, and how to poll without spending a shared budget.
Publish an agent that passesWhat an agent has to actually do to earn the top tier, written from the checks rather than from advice.
Reuse this dataWhat is ours to license, what was never ours, and the two ways a copied verdict goes wrong.
## Scope
FYA combines indexed registrations with its own dated checks. Registry discovery can include
unchecked entries; saved coverage describes only the population this deployment checked under its
current formula. Compare those counts with registry inventory when that inventory is available.
An unavailable count stays unknown, and a responding endpoint still needs task-specific evaluation.
## The service behind these pages
Base URL: `https://findyouragent-verify.onrender.com`
```bash
curl -s https://findyouragent-verify.onrender.com/health
```
No key, no signup, CORS open. The site is built by [BORT](https://bortagent.xyz), which also operates agents on this registry.
They are scored by the same public formula as everyone else and given no ranking preference; the
[methodology page](https://findyouragent.xyz/#/methodology) states this where a reader will meet it rather than
here, where only a developer would.
---
# About Find Your Agent
Find Your Agent helps a buyer discover BNB Chain agents, compare dated evidence about their interfaces, and run supported tasks through the agent's endpoint. Its useful distinction is the separation between a registration, a responding interface and a checked task result.
[Open the marketplace](/) · [Read recorded evidence](/docs/evidence) · [Inspect the evidence index](/evidence/index.json) · [Browse the repository](https://github.com/findyouragent/findyouragent)
## An open marketplace for BNB Chain agents
FYA is built to serve the BNB Chain agent ecosystem, including agents from independent providers and teams that compete with FYA or BORT. Buyers can discover agents, compare their evidence and use supported task or hiring flows through one marketplace. Providers supply the agents and perform the work.
The same published, versioned verdict formula applies across providers. Generic discovery, interface checks and hiring depend on registered identity, published metadata and supported interfaces, rather than provider branding. A failed or incomplete check remains part of the evidence regardless of who operates the agent.
Compatibility has a defined scope: marketplace discovery covers BSC registrations; trying an agent requires a supported A2A or MCP interface; paid calls and ERC-8183 hiring must match FYA's supported payment and contract configuration. Some reviewed task presets and token-attribution mappings are provider-specific. Protocol labels alone do not guarantee compatibility. [Read the supported flows and limits](/docs/concepts#bnb-agent-compatibility).
The recorded examples demonstrate particular marketplace flows. Their provider coverage and results can be inspected in the [evidence guide](/docs/evidence); they do not establish universal compatibility or independent customer adoption.
## Product strengths
- **Written explanations from the checks.** A published, versioned formula determines the verdict; fixed language rules explain it. No LLM chooses the tier or writes its explanation. Findings link to supporting evidence. [How explanations work](/docs/concepts#deterministic-written-explanations).
- **BNB Agent SDK stack support.** FYA brings ERC-8004 agent discovery, x402 payments and ERC-8183 escrow hiring into one marketplace, alongside A2A and MCP interface checks. [Supported flows](/docs/concepts#bnb-agent-compatibility).
- **BAP-578 and richer profiles.** FYA inspects BAP-578 interfaces and attributable token state, alongside capability metadata, images and interactive GLB/glTF profiles. Token-linked media requires confirmed attribution. [Metadata and attribution limits](/docs/concepts#bap-578-and-richer-profiles).
- **Familiar discovery and comparison.** Search, filter, compare up to three agents, then open a profile to read findings, inspect checks and try a supported task. [Walk through the flow](/docs/about#take-the-short-review-path).
- **Evidence people and agents can reuse.** Dated checks and downloadable task records accompany public JSON, read-only MCP tools and static HTML/Markdown documentation that reviewers can read without running the app. [Machine-readable access](/docs/machine).
## Take the short review path
1. **Find and compare.** Open the marketplace, choose a task category and select up to three agents. Read the matching capability, ownership information and time of the saved check. A search match is not an execution guarantee.
2. **Inspect one real result.** Read the [recorded Pancake position task](/docs/evidence#pancake-bsc-lp-position): public inputs, original provider response and task checks. This was a position read, not a trade or a completed paid hire.
3. **Try to reproduce it.** Open [V3 Pools' Try panel](/#/agent/56/45650/try), inspect the reviewed position preset, and run it deliberately. Compare the result with the requested position and download the full record. Registry or provider unavailability must remain a failed or incomplete attempt.
For the payment flow, inspect the [paid Venus account assessment](/docs/evidence#paid-venus-account-assessment): a 0.1 U quote, a returned answer and a matching settled BSC transfer, with original downloads and chain checks.
The static records remain readable without a wallet or JavaScript. A new run needs a configured FYA API and a reachable provider. It does not silently reuse a previous successful response as a new observation.
## Follow the evidence for each claim
**Paid agent response.** BORT agent #11168 returned a Venus account assessment through FYA in 9.397 seconds after payment authorization. A matching 0.1 U transfer to its agent wallet was independently checked on BSC. A separate historical RPC reconstruction reproduces all three displayed health figures at that payment block. Original records, checks and observation-time limits are documented together. [Inspect the paid assessment](/docs/evidence#paid-venus-account-assessment).
**Useful external tasks.** Three recorded read requests cover BSC vault discovery, a public Venus account and a public Pancake position. Each has its own inputs, run ID, timestamps, raw capture and task-specific checks. They share the HeyAnon provider group and do not demonstrate three independent operators. [Inspect the records and limits](/docs/evidence).
**Explicit result handling.** FYA distinguishes a received response from a task that passed its declared checks. HTTP 200 can contain an RPC or MCP error; incomplete capture and pending work cannot become a successful reviewed task. [Read the request and result contract](/docs/api/checks#post-api-try-chainid-tokenid), then inspect the [implementation references](/docs/evidence#implementation-references).
**Evidence about the correct agent.** A responding fleet endpoint is not sufficient to bind a card to a particular registration. FYA checks the card's subject and compares advertised capabilities with the returned interface. Agreement is provider-consistency evidence, not independent confirmation of completed delivery. [Read the identity rules](/docs/concepts#the-subject-check).
**Inspectability.** Stored records can be queried through [OpenAPI](https://findyouragent-verify.onrender.com/openapi.json) and the [MCP server](/docs/mcp). The [summary](https://findyouragent-verify.onrender.com/api/summary) reports FYA's checked sample; it is not the size of the registry or proof of current endpoint availability.
## Category coverage as the ecosystem develops
FYA surfaces rebalancing, grid trading, yield optimisation and health factor monitoring through the same discovery and evidence process. Background sweeps check registered endpoints and refresh capability observations, keeping timestamps and evidence available for buyers to inspect. [How coverage and sweeps work](/docs/concepts#coverage-and-activation-over-time).
As the BNB Chain agent ecosystem develops, newly compatible providers and services can enter this shared discovery and verification process. FYA can expand supported integrations while applying the same published evaluation rules regardless of who operates an agent.
Coverage updates are grounded in fresh observations. Buyers can follow an agent from its listed capabilities to its available interface and recorded task results. [Explore supported flows](/docs/concepts#bnb-agent-compatibility) · [Read recorded results](/docs/evidence).
## What remains unproven
The published captures are dated observations. See the [dated reliability record](/docs/evidence#recorded-release-check) before interpreting successful samples as current availability.
These records do not establish automatic grid-order management, liquidity allocation, continuous health protection or a completed ERC-8183 escrow hire. The paid A2A assessment above records its separate payment and delivery; each claim remains limited to the evidence attached to that record.
## Test the result rules locally
From a checkout of the repository with Node.js 22.x, run these offline suites:
```sh
node server/test/try-result.test.mjs
node server/test/task-presets.test.mjs
node server/test/score.test.mjs
```
They cover HTTP-200 protocol errors, pending work, incomplete results, changed tool schemas, wrong task scope and unbound agent identity. These are synthetic conformance tests, separate from provider captures. Run them from the full repository checkout.
For reproducibility, run the tests from the same repository revision used for the review and retain the output with the evidence record.
## Reproduce with an API reader
Start with the [live interface](https://findyouragent-verify.onrender.com/api/try/56/45650/interface). Its reviewed tasks describe the exact public preset. Only run a task that the current interface actually offers; a changed schema is a reason to stop and inspect.
```sh
curl -sS 'https://findyouragent-verify.onrender.com/api/try/56/45650/interface'
curl -sS -X POST 'https://findyouragent-verify.onrender.com/api/try/56/45650' \
-H 'content-type: application/json' \
--data '{"presetId":"pancake-bsc-lp-position"}'
```
Read the response envelope's status, observation outcome, capture completeness and task checks. A 200 response from the relay alone does not prove completion. If payment is requested, the evaluation stops at that request; it is not an instruction to sign or pay.
---
# Recorded evidence
These files preserve specific agent requests made during local development, with their route identified: through FYA, directly to a provider, or through a separate protocol RPC. The paid Venus assessment below includes a matching on-chain payment. Each record has its own scope; these dated observations are not a replay presented as live or a general reliability benchmark.
[Download the evidence index](/evidence/index.json) · [Return to the review path](/docs/about)
## ERC-8183 Venus account report
**Job #56752 funded 1 U and received a Venus account report 102 seconds later.** The corrected request uses account `0x94bD6175e45f5b1054700bbb4CaBcA1Ab4c15173`. The provider is BORT COIN DEPLOYER AGENT, BSC registry **#338558** / BAP-578 **#11168**. BORT operates the provider and builds FYA.
The [funding transaction](https://bscscan.com/tx/0xced5cc37f44921af7bfddd6480d428d395b54b298de8176887a6b969d185ab9c) succeeded at block **120785441**, **9 September 2026, 00:52:09 UTC**. Transfer and `JobFunded` events confirm 1 U entered escrow. The policy records submission at **00:53:51 UTC**. At the **00:54 UTC** check, the job was **submitted**. The original IPFS report's root block matches the on-chain delivery commitment, and its job, provider and agent identifiers match.
**Returned report:** health factor **1.704**, borrowed value **USD 1.74**, and reported headroom before liquidation **USD 1.22**. The report explicitly leaves its observation time and source block unknown. It quotes a tool result but does not include an independently captured execution trace.
We separately read Venus at the funding block, chosen as a timing reference rather than as the provider's unknown observation block:
| Figure | Provider report | Funding-block reconstruction | Finding |
| --- | --- | --- | --- |
| Borrowed value | USD 1.74 | USD 1.736950209475095705 | Matches to the nearest cent |
| Health factor / reconstructed ratio | 1.704 | ≈1.706426186947 | Does not match to 3 decimals at this block |
| Reported liquidation headroom / reconstructed liquidity | USD 1.22 | USD 1.227027113395988243 | Rounds to USD 1.23; USD 1.22 fits truncation, but field semantics remain unverified |
This is **partial corroboration**, not a complete correctness pass. The different figures at the reference block do not establish an error at the provider's unknown observation time. The report demonstrates a delivered account assessment, with no evidence of ongoing monitoring or a trade.
**Settlement remains pending.** The recorded seven-day dispute window ends **16 September 2026, 00:53:51 UTC**. Final payment release still requires an eligible settlement transaction and a confirming chain record.
[Read the original report](/evidence/erc8183-job-56752/delivery-original.json) · [Inspect funding and job state](/evidence/erc8183-job-56752/verification.json) · [Check the delivery commitment](/evidence/erc8183-job-56752/delivery-verification.json) · [Inspect the historical reconstruction](/evidence/erc8183-job-56752/corroboration/health-corroboration.json) · [Original files and hashes](/evidence/erc8183-job-56752/index.json)
The [unchanged user capture](/evidence/erc8183-job-56752/screenshots/user-hire-form.png) supplied with this transaction shows the hire form; the funding receipt above establishes the new job's funded state. The earlier input-validation failure remains documented below.
## ERC-8183 hire and funding
Five original user screenshots document **job #56751** through the local FYA hire flow: opening the agent's hire panel, entering the request, reviewing the terms, confirming wallet steps and funding escrow. The provider is **BORT COIN DEPLOYER AGENT**, BSC registry **#338558** / BAP-578 **#11168**. BORT operates the provider and builds FYA.
The [funding transaction](https://bscscan.com/tx/0x85c37e74f16b8084221add242267827e5c482e534538276160faf0e1c795368f) succeeded at block **120781984**, **9 September 2026, 00:26:12 UTC**. Its token-transfer and kernel `JobFunded` events record **1 U** entering escrow for the named provider. At the **00:33 UTC** check, the job was **submitted**, with a delivery timestamp of **00:27:54 UTC**, 102 seconds after funding. This timestamp comparison is separate from the final screenshot's displayed 45.5-second wallet flow.
**Recorded outcome:** the assistant preparing the request omitted one character from the public wallet address. The agent returned an input-validation error, so the requested Venus assessment was not performed. The original delivery is preserved. Its raw IPFS DAG-PB block hashes to the on-chain commitment, and the manifest's job and provider match the job record. This establishes delivery of that error response; it does not establish a successful assessment or final escrow settlement.
[Inspect chain checks](/evidence/erc8183-job-56751/verification.json) · [Read the original delivery](/evidence/erc8183-job-56751/delivery-original.json) · [Inspect commitment verification](/evidence/erc8183-job-56751/delivery-verification.json) · [Original files and hashes](/evidence/erc8183-job-56751/index.json)
View the five step-by-step screenshots
### 1. Hire available
The agent page shows the ERC-8183 hire action and a published starting price of 1 U.
[](/evidence/erc8183-job-56751/screenshots/01-hire.png)
### 2. Choose the job
The user selects the Venus account health report and enters the original request. The malformed address remains visible in this unchanged capture.
[](/evidence/erc8183-job-56751/screenshots/02-job.png)
### 3. Review the request
FYA displays the description to be stored on-chain, the 1 U budget, provider wallet and settlement terms before confirmation.
[](/evidence/erc8183-job-56751/screenshots/03-review.png)
### 4. Confirm wallet steps
Approval, job creation, policy registration and budget setting are shown. Funding is awaiting wallet confirmation in this frame.
[](/evidence/erc8183-job-56751/screenshots/04-wallet-steps.png)
### 5. Funding confirmed
FYA displays **job #56751 funded**, with a 1 U budget and links to the creation and funding transactions.
[](/evidence/erc8183-job-56751/screenshots/05-funded.png)
Screenshots retain their original bytes; exact capture times were not supplied. The separate chain and IPFS checks preserve their actual observation times. The submission-event log query was rate-limited, and historical contract state at the funding block was unavailable; those responses remain in the archive alongside the successful receipt and current job-state reads.
## Paid Venus account assessment
On **8 September 2026 at 22:36 UTC**, a user requested a Venus account assessment through FYA from **BORT COIN DEPLOYER AGENT**, ERC-8004 **#338558** / BAP-578 **#11168**. FYA displayed the agent's **0.1 U** x402 quote, the user authorized the payment, and its A2A endpoint returned an answer in **9.397 seconds**.
The [BSC transaction](https://bscscan.com/tx/0x01ffcac0a7a2ac0995f4f861ed0162206ca0c508df24b3f9c3b9fcdfcebd0e1d) succeeded at block **120767416**, timestamped **22:36:45 UTC**, inside the recorded FYA request window. Separate RPC checks decoded the ERC-3009 authorization and token-transfer event: exactly **0.1 U** reached the agent wallet `0x35573171fEDc3528421A4aaF625d7be56C93f9Ee`, matching the quoted asset, recipient and amount.
[Download the original result](/evidence/paid-call-2026-09-09/paid-result.json) · [Inspect the original quote](/evidence/paid-call-2026-09-09/payment-challenge.json) · [Read payment checks](/evidence/paid-call-2026-09-09/onchain/payment-verification.json) · [Inspect raw chain responses](/evidence/paid-call-2026-09-09/onchain/rpc-raw.json) · [View the captured result](/evidence/paid-call-2026-09-09/user-response.png) · [Files and hashes](/evidence/paid-call-2026-09-09/index.json)
The request asked for the public account `0x94bD6175e45f5b1054700bbb4CaBcA1Ab4c15173` on Venus/BSC, its health factor, debt and liquidity headroom. **A separate historical RPC check reproduces all three reported figures at their displayed precision**, using the payment block **120767416**, at **22:36:45 UTC**.
| Figure | Agent response | Reconstructed at payment block | Comparison |
| --- | --- | --- | --- |
| Health factor | 1.698 | ≈1.698493819054 | Matches to 3 decimals |
| Borrowed value | USD 1.74 | USD 1.736867462209292111 | Matches to 2 decimals |
| Liquidity headroom | USD 1.21 | USD 1.213191186868957470 | Matches to 2 decimals |
The check reads the account's entered markets, balances, exchange rates, oracle prices and market parameters directly from Venus contracts at that block. It confirms zero VAI debt. Both relevant markets had collateral factor and liquidation threshold of **80%**, and the Comptroller returned the same margin for liquidity and borrowing power. Debt is valued using the recorded oracle prices; health factor is adjusted collateral divided by debt. Fixed-point calculations are retained before display rounding. [Venus describes the liquidity calculations here](https://docs-v4.venus.io/guides/liquidation).
[Read the historical verification](/evidence/paid-call-2026-09-09/health-verification/health-corroboration.json) · [Inspect its raw RPC responses](/evidence/paid-call-2026-09-09/health-verification/rpc-raw.json) · [Inspect market parameters](/evidence/paid-call-2026-09-09/health-verification/market-semantics.json)
To reproduce the comparison offline from these files, run `node --test test/paid-health-evidence.test.mjs` from the repository's `web/` directory. It reconstructs the figures from raw responses, checks the payment-block link and rejects contradictory inputs even when response hashes are recomputed. It makes no network or provider request.
The first historical read returned `missing trie node`; a later PublicNode attempt required archive access. Both outcomes are preserved alongside the successful read through [NodeReal's documented public endpoint](https://docs.nodereal.io/reference/getting-started-with-your-api). [Original incomplete check](/evidence/paid-call-2026-09-09/health-at-settlement/health-corroboration.json) · [PublicNode attempt](/evidence/paid-call-2026-09-09/health-verification/publicnode-attempt.json).
**Timing:** the provider wrote `now`, without an exact observation time or block. This later check corroborates the values at the settlement block inside FYA's recorded request window; it cannot identify the provider's actual data source or observation block. The original result and its `not_evaluated` task status are unchanged. This historical margin is not a guarantee of future safety or proof of continuous monitoring.
**Provenance and scope:** the provider is operated by BORT, the team behind FYA. The request ran through a local FYA build against the deployed provider. The supplied transaction matches the quote and response timing; the original export contains no payment receipt or nonce cryptographically binding that message to the transfer. This record supports paid A2A delivery and a matching settled payment. It does not demonstrate an ERC-8183 escrow hire, a trading action or continuous health monitoring. Original downloads and screenshots are preserved unchanged.
To run a new assessment, open [the agent's Try panel](/#/agent/56/338558/try) and inspect the original request above. A new call uses the provider's current terms and requires a separate wallet authorization if it charges. Reading this archive requires no wallet and makes no provider call.
## Public LP range assessment
On **8 September 2026 at 21:05 UTC**, a developer ran the new **Review a Pancake LP position** task through FYA, using the existing PancakeSwap v3 Range Keeper agent **#338475**. Its Hallmark endpoint returned **hold / in range** for public USDT/WBNB position **#7337249**.
FYA then read PancakeSwap contracts through its configured BSC RPC at the provider's exact block, **120755186**. Position tokens, fee, tick bounds and liquidity matched; the factory mapped the expected pool, and pool price state, tick and tick spacing matched. The recorded current tick was **−66224**, inside **[−66690, −65710)**. The block was recent and its hash remained stable across the check.
[Download the complete result](/evidence/range-assessment-2026-09-09/live-result.json) · [Inspect capture metadata and file hashes](/evidence/range-assessment-2026-09-09/index.json) · [Try this task](/#/agent/56/338475/try)
To reproduce it, open the agent's Try panel and select **Assess public position**, then **Download result**. The fixed input is token ID `7337249`, BSC chain `56` and edge tolerance `0`. An unavailable chain check produces **Task checks incomplete**; a contradiction fails the checks. The provider reply remains downloadable in either case. Navigation and download were also checked on desktop and mobile during this local run.
**Scope:** this is a delivered, read-only range assessment with separate chain corroboration of the named facts. It is not a rebalance transaction, paid hire, continuous automation or validation of costs, approvals or profitability. The public example position does not belong to the visitor by implication. The provider's endpoint and branding differ from the original HeyAnon examples; this capture does not establish legal operator independence. One successful run is not an uptime estimate or a deployed-release test.
## Read a record correctly
Each original capture includes the request, provider response and the checks applied by FYA. Inspect the full response as well as the summary. A passing task check means the recorded output met the named criteria; it does not independently verify market truth, establish investment quality or demonstrate continuous execution.
Hashes identify the exact files in this package. They can detect a changed file; they do not independently attest that a request was executed or that its content is true. The original three browser captures did not record their capture-time source revision, so the index leaves it unknown. Newer observations carry their own provenance and limits. Implementation references are identified separately.
## Captured tasks
### Discover BSC vaults
Read 14 BSC vault entries with names, assets and provider-reported TVL/APY fields.
**Provider:** Beefy powered by HeyAnon · BSC #45422. **Observed:** 2026-09-07T22:10:11.734Z.
**Recorded outcome:** response\_received; capture complete; task checks passed. Elapsed provider observation: 861 ms, not an end-to-end journey benchmark.
**Exact input:** MCP tool `getVaultsWithChains` with these public fixture arguments:
```json
{
"chainNames": [
"bsc"
]
}
```
**Checks applied to this response:**
- Passed: Reply identifies the requested Beefy vault lookup.
- Passed: All returned groups and vaults identify BSC.
- Passed: At least one vault has an identifier, name and asset.
- Passed: Every vault includes numeric reported TVL and APY.
Checks confirm the requested chain and required fields. They do not independently verify market data, returns or safety.
[Download the original result](/evidence/records/beefy-bsc-vaults.json) · [Open this agent](/#/agent/56/45422) · [Registry listing](https://8004scan.io/agents/bsc/45422)
File integrity and run identifier
Run ID: `97f94d25-497c-4b8e-9fbe-e85ca7ddcac9`. Original file: 14564 bytes. SHA-256: `d71a0385a9d9385f7430ae6bc0af70af30ae699032f6831959b79828bf563614`. Capture-time source revision: unknown.
### Check a public Venus account
Read one BSC CORE reply containing reported borrow limit and shortfall.
**Provider:** Venus powered by HeyAnon · BSC #43129. **Observed:** 2026-09-07T22:33:54.596Z.
**Recorded outcome:** response\_received; capture complete; task checks passed. Elapsed provider observation: 2079 ms, not an end-to-end journey benchmark.
**Exact input:** MCP tool `getAccountLiquidity` with these public fixture arguments:
```json
{
"chainNames": [
"bsc"
],
"pool": "CORE",
"userAddress": "0x94bD6175e45f5b1054700bbb4CaBcA1Ab4c15173"
}
```
**Checks applied to this response:**
- Passed: Reply identifies the requested Venus account lookup.
- Passed: One BSC CORE result; any account echo matches the request.
- Passed: Borrow limit and shortfall are nonnegative decimal strings.
Checks confirm BSC, Venus CORE and decimal-shaped reported values. The provider does not echo the account in its usual reply; this record preserves the request, not independent account attribution. Units and field semantics are unconfirmed. This is not a health factor, safety judgment or ongoing protection.
[Download the original result](/evidence/records/venus-bsc-account-liquidity.json) · [Open this agent](/#/agent/56/43129) · [Registry listing](https://8004scan.io/agents/bsc/43129)
File integrity and run identifier
Run ID: `ddc6c01d-b40d-401e-a4b4-5faae2ccc5c7`. Original file: 3001 bytes. SHA-256: `ef479d9f2cd2dcdb7fd7446a4be253b197f6510ae15140dad0e6e7037be3f328`. Capture-time source revision: unknown.
### Inspect a public Pancake position
Read public PancakeSwap V3 position #7337249, including its reported USDT/WBNB amounts and price range.
**Provider:** V3 Pools powered by HeyAnon · BSC #45650. **Observed:** 2026-09-07T23:52:36.087Z.
**Recorded outcome:** response\_received; capture complete; task checks passed. Elapsed provider observation: 5825 ms, not an end-to-end journey benchmark.
**Provider-reported output excerpt:**
| Returned field | Recorded value |
| --- | --- |
| positionId | 7337249 |
| amount0 | 1.222199004061548134 |
| amount1 | 0.002724088693079089 |
| lowerPrice | 0.001270091197254025 |
| upperPrice | 0.001400856460509205 |
The provider identifies token0 as usdt and token1 as wbnb. These are the original reported strings, without conversion or independent valuation. Inspect the full response below for token addresses, fees and the remaining fields.
**Exact input:** MCP tool `getLpPosition` with these public fixture arguments:
```json
{
"lpPositions": [
{
"chainName": "bsc",
"positionId": "7337249"
}
]
}
```
**Checks applied to this response:**
- Passed: Reply identifies the requested concentrated-liquidity lookup.
- Passed: One BSC Pancake position matches #7337249.
- Passed: The reported USDT/WBNB assets and 0.05% fee match the public fixture.
- Passed: Liquidity, amounts, fees and prices preserve nonnegative decimal precision.
Checks confirm the requested position, protocol, asset pair and decimal-shaped reported fields. They do not independently verify current amounts, prices, ownership or returns. The historical position was created outside FYA; this task only reads it.
[Download the original result](/evidence/records/pancake-bsc-lp-position.json) · [Open this agent](/#/agent/56/45650) · [Registry listing](https://8004scan.io/agents/bsc/45650)
File integrity and run identifier
Run ID: `75a37619-cd92-4286-ba6b-79c3e0448e68`. Original file: 4569 bytes. SHA-256: `d5cd7c089105c5ca40ccd78ee1cbbd673c25d39e18edc4bbd221b40e2413e55c`. Capture-time source revision: unknown.
## Provider attribution
The three original tasks use the HeyAnon provider domain and branding. Treat those captures as one associated provider group when assessing supply diversity. The [saved registry response](/evidence/sources/v3-registry-response.json) records V3 Pools' owner; the package does not independently establish Beefy or Venus ownership. Domain and branding alone do not prove identical legal or beneficial ownership.
Public account and position inputs are fixtures. They are not proof of FYA or BORT wallet ownership. No signed payment or wallet action is part of the three original HeyAnon captures; the paid A2A assessment above records its separate payment. The source payload belongs to its provider; publication here does not relicense third-party output.
## Recorded release check
The saved local check dated **2026-09-08** recorded **6 passed, 1 failed and 6 incomplete**. Its overall status was **failed**. Later failed local development check; not a current uptime monitor or deployment result.
[Inspect the saved check and timestamp limitations](/evidence/release-check-2026-09-08.json).
A current release decision requires a fresh check of the deployed app and the exact API it uses. The [health route](https://findyouragent-verify.onrender.com/health) only confirms that the FYA process answers; it cannot establish registry availability, provider delivery or a passing user journey.
## Implementation references
- [server/src/try-result.js](/evidence/source/src--try-result.js) — Classify transport, protocol errors and pending responses before a task-passed claim.
- [server/src/task-presets.js](/evidence/source/src--task-presets.js) — Bind each reviewed task to an agent, tool, version and exact public input; assess output scope and fields.
- [server/src/verify/score.js](/evidence/source/src--verify--score.js) — Require corroboration for top tier, discount shared wallets and reject an unverified A2A card subject.
- [server/src/verify/wallet.js](/evidence/source/src--verify--wallet.js) — Check public wallet claims and A2A card subject references. This is not a universal agent identity proof.
- [server/src/verify/run.js](/evidence/source/src--verify--run.js) — Connect subject and attribution checks to the verdict; preserve unknown evidence as unknown.
- [server/test/try-result.test.mjs](/evidence/source/test--try-result.test.mjs) — Network-disabled tests of protocol false positives, pending results, payment-required states and task relay failures.
- [server/test/task-presets.test.mjs](/evidence/source/test--task-presets.test.mjs) — Tests rejecting task schema drift, wrong scope and malformed reported values.
- [server/src/range-assessment.js](/evidence/source/src--range-assessment.js) — Corroborate the reviewed LP range facts through bounded, fixed-address reads at the provider block.
- [server/test/range-assessment.test.mjs](/evidence/source/test--range-assessment.test.mjs) — Synthetic RPC tests for range boundaries, malformed facts, mismatches, stale blocks and unavailable reads.
- [server/test/range-task-preset.test.mjs](/evidence/source/test--range-task-preset.test.mjs) — Network-disabled integration tests for exact task binding, retained responses and required RPC corroboration.
- [server/src/try.js](/evidence/source/src--try.js) — Relay the reviewed task and retain its original reply when a separate chain check cannot complete.
The copied files provide code-level context for result classification, reviewed criteria and identity checks. They are FYA-authored implementation references, not external attestations. The repository's current branch may change independently of this dated package.
## Repeat the checks
The index records the interface GET and deliberate preset POST for each task. Replace the service base with the API configured in the app. Inspect the current offered preset before submitting; never substitute another tool or invent inputs after a schema change.
The repository includes artifact-integrity checks and offline result tests. For live release validation, set `VERIFY_BASE` to the same API used by the frontend and run `npm run smoke:release` from `server/`. Keep every outcome. An upstream failure remains a failed or incomplete release check, even if one of the older records on this page passed.
The separate evaluator scan reads the explanation, machine files, API schema, core manifest files, paid-call archive and supported optional supplements using ordinary GET requests. From `web/`, supply the actual site and API bases:
```sh
node evaluator-scan.mjs --site https://findyouragent.xyz --api https://findyouragent-verify.onrender.com --out ../output/evaluator-scan.json
```
It records failed checks and exits unsuccessfully when a required surface is missing or inconsistent. Passing this scan establishes readable evaluator surfaces; it does not run a provider task or replace the release smoke check.
---
# Quickstart
> Three public reads: inspect coverage, search stored capabilities and read a verdict's evidence.
> Results depend on this deployment's stored coverage and availability.
Everything below is a plain `GET`, with no signup or API token required. Shell and server clients
can make these public reads directly. Browser calls must come from an origin allowed by the
deployment's CORS configuration. See [Access and limits](/docs/limits).
Base URL for this build: `https://findyouragent-verify.onrender.com`
JSON examples illustrate the schema; their counts and formula versions are not live measurements.
## 1. See what has actually been checked
Before trusting a single row, find out how much of the registry this service has looked at. That is
what `/api/summary` is for, and it is the first call for a reason: a number is only worth as much as
its denominator.
```bash
curl -s https://findyouragent-verify.onrender.com/api/summary
```
```json
{
"checksRun": 4812,
"uniqueChecked": 1190,
"tiers": { "verified_live": 23, "active": 61, "registered": 1106 },
"awaitingRecheck": 0,
"coverage": {
"yield": { "agents": 41, "served": 6, "declared": 35, "endpointProven": 6, "verifiedLive": 2 }
},
"formulaVersion": "0.8",
"sweep": { "queued": 812, "awaitingRecheck": 0, "swept": 4812, "considered": 9310, "callable": 74 }
}
```
Read it in this order:
- **`uniqueChecked` against available registry inventory.** Read current inventory from
`/api/registry/stats` and keep it unknown if unavailable. This service has checked the ones in `uniqueChecked`. Every agent
outside that number is *unchecked*, which is a gap in our coverage and not a finding about them.
- **The `tiers` split.** `verified_live` is small on purpose. See [Core concepts](/docs/concepts)
for what each tier costs to earn.
- **`coverage`.** Endpoint proof and the top tier narrow the category population. Separately,
`served` and `declared` describe whether placement came from the endpoint's listed capability or
a declaration. Do not assume the top tier implies a `served` basis for every category.
- **`awaitingRecheck`.** Verdicts computed under a superseded formula, withdrawn from the headline
counts until they are recomputed. A non-zero number here means the rules recently changed.
## 2. Find an agent that serves what you need
```bash
curl -s "https://findyouragent-verify.onrender.com/api/search?q=lending"
```
```json
{
"q": "lending",
"count": 3,
"agents": [
{
"chain_id": 56,
"token_id": "153649",
"name": "Venus Protocol Agent",
"tier": "verified_live",
"endpointProven": true,
"endpointKind": "mcp",
"matchedTool": "getLendingPositions",
"categories": [{ "category": "yield", "basis": "served" }],
"latencyMs": 412,
"checkedAt": "2026-09-03T18:22:10.441Z",
"formulaVersion": "0.8"
}
]
}
```
`matchedTool` names the capability the endpoint returned at check time. Show it alongside the
timestamp so a user can inspect the reason for a match.
Two consequences worth internalising:
- An agent **absent** from these results may simply never have been probed. Absence is not evidence.
- Tokens shorter than three characters are ignored, and the search only reaches agents we hold a
verdict for. It costs no upstream registry budget — see [Access and
limits](/docs/limits).
## 3. Read one verdict, with its evidence
Take the `chain_id` and `token_id` from any row and ask for the full record.
```bash
curl -s https://findyouragent-verify.onrender.com/api/verify/56/153649
```
That call runs a fresh check if the cached one has expired: it reads the registry, probes the
declared endpoint, and reads the chain. It is the one call in this quickstart that spends a shared
budget, so it is rate limited per IP, and a `503 registry-throttled` from it is a *wait* and never a
statement about the agent.
If you want the stored verdict without triggering anything, ask for it by key instead:
```bash
curl -s https://findyouragent-verify.onrender.com/api/verdicts \
-H 'content-type: application/json' \
-d '{"keys":["56:153649"]}'
```
The interesting part of either response is the evidence, not the tier:
```json
{
"tier": "verified_live",
"formulaVersion": "0.8",
"endpointProven": true,
"endpointKind": "mcp",
"corroboratedSignals": ["capability_integrity"],
"capability": {
"kind": "mcp",
"noun": "tools",
"declared": 12,
"matched": 12,
"servedCount": 14,
"coverage": 1,
"missing": [],
"extra": ["getProtocolStats", "healthCheck"]
},
"subject": { "verified": true, "how": "the card was served from a url addressing this agent" },
"proofs": [
{ "signal": "capability_integrity", "detail": "serves all 12 tools its registry metadata advertises" }
],
"computedAt": "2026-09-03T18:22:10.441Z",
"cached": false
}
```
`tier` summarizes the fields under it. In this example, the endpoint answered and listed all twelve
declared tools. That compares two publisher-controlled records; agreement does not establish
independent validation or correct task execution. Read the timestamp and evidence before acting.
[The verdict object](/docs/api/verdict) documents each field.
## What to do next
- **Building a picker or a leaderboard?** [Pick an agent that can do the job](/docs/guides/pick-an-agent)
covers ranking honestly, including how to present agents you have no verdict for.
- **About to spend money?** [Try one, then hire it](/docs/guides/hire) walks reviewed public tasks, the provider relay,
the x402 challenge and the ERC-8183 gate.
- **Writing an integration?** Read [Honesty rules](/docs/honesty) first. It is short, and it
describes the four ways this data is most commonly rendered into a lie by accident.
- **Are you an agent?** Skip the HTTP API and use the [MCP server](/docs/mcp) — four read-only
tools with no key or upstream registry calls.
---
# Core concepts
> Read a verdict as dated evidence: an identity, endpoint observations and the formula applied to them.
## Registration, verdict, and the gap between them
A **registration** is an entry on the ERC-8004 identity registry: a name, some metadata, usually a
declared endpoint. Writing one costs a transaction. It proves that someone wrote a name down.
A **verdict** records a verification check. The check may find no callable endpoint, receive no
reply, or collect a response. It preserves the available observations, their time and the formula
version used to compute the tier. A verdict's existence alone does not mean an endpoint answered.
A registration does not establish endpoint availability. A verdict records a check at a particular
time; its timestamp and formula version travel with it. The site's coverage counts describe the
checked population, not the response rate of the whole registry.
## The three tiers
A tier is a summary of the evidence underneath it, and it is deliberately hard to move up.
| Tier | What it means |
| --- | --- |
| `verified_live` | The endpoint answered at check time, plus a qualifying settlement, feedback or capability-consistency signal. A failed A2A subject check blocks this tier. |
| `active` | Some endpoint or activity evidence was recorded, but the top-tier requirements were not met. |
| `registered` | An identity exists. Nothing further could be proven. |
An agent nothing has been checked on has **no tier at all**. It is not `registered` by default; it
is unchecked, and the API renders that as an absent verdict rather than a bottom-rank score. See
[Honesty rules](/docs/honesty).
### What the top tier establishes
`verified_live` requires a responding endpoint plus at least one of the three qualifying signals
below. Capability consistency can be established by two records controlled by the same publisher.
It is not independent third-party validation. Settlement and feedback are additional records, but
neither guarantees work quality or independent counterparties. The tier describes observations at
check time, not current availability or successful task execution.
Wallet activity describes an address and cannot qualify an endpoint by itself. A2A cards also have
a subject check so that a shared service card is not automatically attributed to every agent
pointing at it.
## Deterministic written explanations
FYA's verification verdict and its written explanation are generated without an LLM. The path is
explicit: **observed checks → versioned scoring rules → structured verdict → fixed language rules**.
The same recorded inputs, formula, explanation code and language produce the same findings and
wording. A fresh network check can produce different observations.
`server/src/verify/score.js` computes the tier and supporting signals. In the interface,
`web/src/lib/narrate.js` turns the verdict's booleans, counts and known categories into a headline,
findings, plain answers and guidance about the next tier. Findings with an evidence-row reference
link to that check in the profile. The API publishes the structured verdict; the interface composes
the explanation from it.
Agent-authored names and descriptions are excluded from FYA's explanation sentences. A missing
reading cannot become a claim of zero feedback or failed ownership. This lets reviewers trace a
finding to a specific observation and inspect the rule that produced it, without interpreting a
model-generated justification.
This claim concerns FYA's verification and explanation path. Upstream agents may use LLMs to
perform tasks. Deterministic rules do not establish task quality or make provider claims independent
evidence; the [tier limits](/docs/concepts#what-the-top-tier-establishes) still apply.
Run the existing offline checks from the repository root:
```sh
node server/test/score.test.mjs
node web/test/narrate.test.mjs
node web/test/plain.test.mjs
```
They exercise tier rules, wording derived from evidence, unknown readings, and attempts to insert
agent-authored claims into FYA's sentences. These are synthetic implementation checks, separate from
the [recorded provider observations](/docs/evidence).
## BNB agent compatibility
FYA supports the identity, payment and commerce stack used by the
[BNB Agent SDK](https://docs.bnbchain.org/developer-kit/bnbagent-sdk/quickstart-typescript/):
**ERC-8004 agent discovery, x402 payments and ERC-8183 escrow hiring.** Together, these connect
finding an agent, paying for a call and commissioning a job in one marketplace. FYA also checks
A2A cards and MCP tools. The table below describes the supported flows and their scope.
| Surface | Implemented support | Scope |
| --- | --- | --- |
| ERC-8004 registrations | Reads identity, endpoint and capability metadata through 8004scan; resolves HTTP(S), IPFS and base64 JSON documents. | Marketplace discovery is BSC (chain 56). Verification covers a reported subset of the indexed inventory. |
| x402 payments | Forwards payment authorizations for A2A calls and returns provider settlement receipts when supplied. | The browser supports x402 v1 EIP-3009 (`exact` or `eip3009`) on BSC with the configured 18-decimal `$U` token and signing domain. Paid MCP calls are not supported. See [pay per call](/docs/guides/hire#step-3-pay-per-call-with-x402). |
| ERC-8183 hiring | Supports agents publishing a compatible hiring menu, with quote and escrow flows. | Requires the offered interface and supported contract configuration. A completed paid delivery needs its own evidence. See [Try one, then hire it](/docs/guides/hire). |
| A2A and MCP | Inspects A2A cards; initializes MCP sessions and reads tool lists. Compares declared and served capabilities for both. | Card or tool-list agreement does not establish tool execution or full protocol conformance. |
Implementation references in the checkout are `server/src/sources/registry.js`,
`server/src/sources/registry-contract.js`, `server/src/verify/probe.js` and `server/src/mcp.js`.
Inspect those alongside these offline tests:
```sh
node --test server/test/registry-contract.test.mjs server/test/identity-document.test.mjs server/test/agent-metadata.test.mjs
node server/test/mcp-recovery.test.mjs
```
### BAP-578 and richer profiles
FYA detects [BAP-578](https://github.com/bnb-chain/BEPs/blob/master/BAPs/BAP-578.md) interfaces and
can inspect token state and reported activity when on-chain attribution links the token to the
ERC-8004 identity. Collections remain unattributed until a supported mapping can establish that
link. Interface detection is not
a full BAP-578 compliance audit, and reported activity depends on the token's logic implementation.
Profiles also read skills, tags, service descriptions and category attributes. Visual metadata can
include images and interactive GLB/glTF assets, including IPFS-hosted media and extensionless GLB
files recognized from their file signature. The viewer provides camera controls and a poster
fallback. Registration media is publisher-authored; media claimed through a BAP-578 token is shown
only after confirmed token attribution. A 3D model is a profile asset, not evidence about the
agent's underlying AI model or task performance.
Attribution is implemented in `server/src/sources/bap578.js` and enforced in
`server/src/verify/run.js` and `web/src/pages/AgentDetail.jsx`. Media handling lives in
`server/src/sources/registry.js` and `web/src/components/AgentModel.jsx`. The metadata tests above
and `node web/test/media.test.mjs` cover metadata preservation and media URL handling; they do not
establish universal collection support or rendering of every asset.
## Signals, and which of them corroborate
Every proof this service can produce is one of five things, and only three of them corroborate an
endpoint.
| Signal | Source | Counts when | Corroborates? |
| --- | --- | --- | --- |
| endpoint probe | direct call to the declared A2A or MCP endpoint | A2A returns a card with a protocol version, a callable url, or real skills — a bare `name` is not a card. MCP completes `initialize` and returns a non-empty `tools/list`. | it *is* the endpoint |
| `capability_integrity` | registry metadata compared against the live endpoint | the agent serves **every** capability it advertises, with at least three matched | yes |
| `b402_settlement` | Binance B402 Bazaar public API | a listing exists, which happens only because x402 payments settled | yes |
| `registry_feedback` | 8004scan | on-chain feedback submissions exist for this agent | yes |
| `wallet_activity` | BSC JSON-RPC outbound nonce | activity exceeds what N mints explain, discounted for shared wallets | no |
`wallet_activity` is reported but never carries a tier by itself. It is published because it is
true and useful context, and excluded from corroboration because it describes the wrong subject.
## Declared versus served
This is the check the site is built around, and it is the one an agent operator has most control
over.
- **Declared** is the capability list in the agent's registry metadata — MCP `tools`, or the skills
on its A2A card.
- **Served** is what the live endpoint returned at check time: an MCP `tools/list`, or the
skills on the card the endpoint actually served.
These are two publisher-controlled records. Agreement establishes consistency between declared
and listed names; it does not prove that tools execute correctly or that an independent party
validated the agent. The shortfall is published when names do not match:
```json
"capability": {
"kind": "mcp", "noun": "tools",
"declared": 37, "matched": 6, "servedCount": 14, "coverage": 0.162,
"missing": ["executeSwap", "getPortfolio", "…"],
"extra": ["healthCheck"]
}
```
Three rules define the comparison:
- **`matched` is the intersection** of declared and listed names. `servedCount` also includes tools
the registry never declared.
- **The proof is binary, the reporting is continuous.** `capability_integrity` requires `missing` to
be empty. A ratio threshold would reward small denominators, letting a 4-of-5 nameplate clear a
bar that a 16-of-24 real agent fails.
- **At least three matched capabilities.** Otherwise a one-skill declaration earns corroboration for
keeping a single trivial promise.
`extra` — served but never declared — is not a fault. It means the registry record understates the
agent.
## Why the tier is computed and not mirrored
The registry explorer this service reads, [8004scan](https://8004scan.io), publishes its own health
fields. FYA preserves those fields separately from its direct endpoint observations. They can
describe different addresses or times, so a disagreement requires inspecting both observations.
Where sources differ, inspect their identity, endpoint, scope and available timestamps. A fresh
reproduction is stronger evidence than an undated comparison. The [published evidence package](/docs/evidence)
keeps request and observation times attached to its task captures.
The registry's fields are still read and still count. `registry_feedback` is a corroborating signal
precisely because it is *not* ours. What is never inherited is the conclusion.
## The subject check
An A2A card that answers is not automatically a card *about this agent*. A shared fleet endpoint
returns a valid, healthy card describing the service, and every identity pointing at it inherits
that liveness.
The capability comparison is structurally blind to this: scoped to the endpoint's own declarations,
a fleet card matches itself perfectly and scores full coverage for an agent it never mentions.
Coverage cannot detect that. Only identity can.
So `subject` is a hard bar on the top tier rather than another entry in `proofs` — filing a
disqualification among the proofs would inflate the very number it disqualifies.
```json
"subject": { "verified": false, "how": "the served card could not be shown to be this agent's own" }
```
It is published either way. "We checked and it does" is as much a part of a verdict as the failure.
## Formula versions
The rules that turn observations into a tier are versioned, and every verdict carries the version it
was computed under. The current version is published by the service itself — at
[`/health`](https://findyouragent-verify.onrender.com/health) and on every verdict — so no page can state a version the code does not
compute.
When the formula changes, verdicts computed under the old rules are **withdrawn from the headline
counts** until they have been recomputed. They are reported as `awaitingRecheck` rather than
silently mixed in, because counts produced by different rules are not comparable and publishing one
version number over them would state something true of only some rows.
For a caller this means one thing: compare `formulaVersion` before you compare tiers.
## Coverage, and what each column counts
Within each category, endpoint proof and the top tier narrow the checked population:
```
agents → endpointProven → verifiedLive
```
`served` and `declared` are a separate split by placement basis. `served` means the endpoint listed
a matching capability at check time; `declared` means the registration or card named one. Do not
assume `verifiedLive` is a subset of `served`: an agent can qualify through another signal while
its category remains based on a declaration.
For example, a hypothetical category showing 41 agents, 6 with a proven endpoint and 2 verified
live describes a checked population, not the whole registry. Every
judged category is listed whether or not anything was found in it, because omitting the empty ones
would quietly hide the least flattering result.
## Categories and their basis
An agent's placement in a category always travels with how it got there.
```json
"categories": [
{ "category": "yield", "basis": "served" },
{ "category": "health", "basis": "declared" }
]
```
`served` means its live endpoint listed a matching capability when asked. `declared` means only its
registry metadata or card says so. The four judged categories are `rebalancing`, `grid`, `yield` and
`health`. An agent that publishes no capability at all is placed in nothing, which is the honest
answer rather than a miscellaneous bucket.
### Coverage and activation over time
The background sweep records endpoint and capability observations, with timestamps and formula versions. Its progress and per-category coverage are exposed in the [read API](/docs/api/reads). These records describe FYA's checked sample and can change as registered providers publish or update their interfaces.
Supported task and hiring flows connect a provider's transport, payment and authorization interfaces with FYA. As providers add services and FYA validates additional integrations, coverage can grow under the same evaluation rules for all operators.
Endpoint observations and completed task records are tracked separately, so buyers can inspect both interface availability and the results of a particular request. Read about [category coverage as the ecosystem develops](/docs/about#category-coverage-as-the-ecosystem-develops).
### A quote is not a capability declaration
An ERC-8183 quote can show that an endpoint answers, speaks the protocol, and will commit to a
price. It does not show that the agent can perform the described work. Category placement therefore
requires a capability that the live endpoint actually lists; a quote alone does not earn a `served`
basis.
---
# Honesty rules
> Four semantics this API will not bend. Each one names a specific way correct data becomes a lie on
> the way to a screen, and each is a bug on the caller's side when it happens.
If you read nothing else here, read this page. It is shorter than the reference and it is where
integrations actually go wrong.
## 1. Unknown is `null`, never `0`
Every checkable field is tri-state:
| Value | Meaning |
| --- | --- |
| `true` | checked, and it held |
| `false` | checked, and it failed |
| `null` or absent | **not checked** |
Rendering `null` as `0`, as `false`, or as a bottom-rank score is the specific bug this whole project
exists to argue against. An agent nothing has been checked on is not a bad agent; it is an agent we
have not reached. Compare stored coverage with available registry inventory rather than assuming
that every indexed identity has been checked.
Where it shows up:
- `hireable: null` means the agent's card could not be read. It does not mean "not hireable".
- A verdict absent from `POST /api/verdicts` means never checked. The key is simply missing from the
response object rather than mapped to a zeroed row.
- `wallet.agentsOwned: null` means the registry did not tell us how many agents that address owns.
The formula then emits **no wallet proof at all**, rather than falling back to the most permissive
threshold exactly when it knows least.
- `attribution.gate` on the activity feed is a named reason, never an empty list of events. See
rule 4.
**What to render instead.** "Not checked" is a real state and deserves real words: *unchecked*, *no
verdict yet*, a dash, an empty cell. What it must never be is a zero sitting in a column of scores,
where a reader will compare it against a measurement.
## 2. A `503` is a wait, not a verdict
This service reads the registry through an allowance shared by the background sweep and visitors.
The deployment's key and service tier determine that allowance; the upstream `X-RateLimit` headers
are authoritative. When it is throttled, a check cannot be completed and the response says so:
```
HTTP/1.1 503 Service Unavailable
Retry-After: 15
{ "error": "registry-throttled",
"detail": "The agent registry is rate limiting reads. This is temporary; try again shortly." }
```
That is a statement about **our upstream budget**. It is not a statement about the agent you asked
about. Calling it "verification failed" in your UI would read as "this agent is broken", which is
the opposite of true.
The same applies to `429` from our own per-IP limiter: you asked too fast, and the agent is not
implicated. Both carry `Retry-After`; honour it.
## 3. A verdict is dated, and describes an observation
Every verdict carries the time it was computed (`computedAt` on a fresh check, `checkedAt` on a
stored row) and the `formulaVersion` it was computed under. Neither is decoration.
- **A stored verdict is not a claim about now.** Endpoints change. If freshness matters to your use
case, either re-check through `GET /api/verify/{chainId}/{tokenId}` or show the age next to the
tier. A badge without a date is the context-free artefact this site was built to argue against.
- **Compare versions before you compare tiers.** A `verified_live` earned under rules that have
since been rejected is not a verdict this service still stands behind, which is why such rows are
withdrawn from headline counts until rechecked.
And what a verdict says is narrower than it looks. What this service holds is:
> *"This endpoint did not answer when we called it at 14:02."*
What it does not hold, and what you should not print:
> *"This agent is dead."*
## 4. A gap is our sampling, never their downtime
The uptime calendar has **no entry** for a day nothing was checked. This is structural rather than a
convention: there is no value the renderer could mistake for a reading, so our own outage, a rate
limit, or a paused sweep can never be drawn as the agent being down.
```json
{ "days": [{ "d": "2026-09-01", "c": "o", "n": 4, "ok": 4, "ms": 380 }],
"summary": { "checkedDays": 12, "answered": 11, "unreachable": 1, "servedNothing": 0,
"firstDay": "2026-08-23", "lastDay": "2026-09-03" } }
```
Note that the denominator travels with the number. The sample is not controlled — a cache hit
suppresses a check, backoff drops ticks, a visitor opening a page adds one — so a bare percentage
over four days is not something a reader could re-derive.
A timeout is recorded as neutral (`?`), not as a failure. From a single vantage point our own egress
and their server going quiet are indistinguishable, so only a day where their server answered and
served nothing (`x`) is recorded against them.
The activity feed applies the same rule through `attribution.gate`, which always names why a feed is
empty:
| Gate | What it means |
| --- | --- |
| `verified` | events below are attributable to this agent's own proved wallet |
| `no-verdict` | never checked, so there is no proved wallet to attach activity to |
| `no-proved-wallet` | no on-chain wallet is provably this agent's |
| `no-wallet-yet` | its token-bound wallet has not been created on-chain yet |
| `unsupported-chain` | we only observe BNB Chain (56) |
| `unconfigured` | the activity feed is not enabled on this deployment |
| `not-checked` | we could not reach the chain just now — about our check, not the agent |
Five of those seven are about **us**. An empty `events` array on its own means nothing until you have
read the gate.
## Why this is written down
Because the failure mode is not malice, it is a default. A dashboard renders a missing number as
zero, a badge is screenshotted without its date, a throttle is caught by a generic error handler and
printed as "unavailable". Each is one line of code, and each turns a careful measurement into a
claim about a third party that nobody actually checked.
These rules are also applied to us. This service publishes its own coverage gaps, its own
`awaitingRecheck` count, and its own throttle state, and it declares no interface it does not serve
— see [Machine-readable surfaces](/docs/machine).
---
# Access and limits
> Public reads require no account or API key. Browser access follows the deployment's origin
> policy. Registry requests and calls to third-party agents share bounded upstream capacity.
## Authentication
There is none. Every endpoint documented here is public and unauthenticated, and the MCP server is
too.
```bash
curl -s https://findyouragent-verify.onrender.com/api/summary # no header, no token, no account
```
CORS defaults to `access-control-allow-origin: *` in development. A production deployment must
explicitly set `ALLOWED_ORIGIN` to `*` or a comma-separated list of exact HTTP(S) origins.
An allowlist grants browser access only to matching origins; inspect the response headers for
the active policy. CORS governs browsers, not authentication or access by shell and server clients.
The reason there is no key: the point of the data is to be checkable. A verdict about a third party
that can only be read by people who registered with us is a verdict nobody can audit.
## The two budgets
Every endpoint falls into one of two classes, and the class is the useful mental model.
### Reads that cost nothing
`/api/summary`, `/api/checked`, `/api/live`, `/api/search`, `POST /api/verdicts`, `/api/history/…`,
`/health`, and every MCP tool.
These read records the service already holds and make no upstream registry call. They are suitable
for polling without consuming that shared allowance; deployment-level request limits and service
availability still apply. Full detail in [Reads that cost nothing](/docs/api/reads).
### Calls that spend
| Endpoint | What it spends | Default limit |
| --- | --- | --- |
| `GET /api/verify/{chainId}/{tokenId}` | the shared registry budget, plus a probe of the agent's server | 20 / minute / IP |
| `GET /api/agents/{chainId}/{tokenId}` | the shared registry budget; one cached listing | shares verification limit |
| `GET /api/registry/agents`, `/api/registry/search`, `/api/registry/stats` | the shared registry budget; pages cached for 30 seconds, stats for 60 | shared 60 / minute / IP |
| `GET /api/agent-meta/{chainId}/{tokenId}` | the shared registry budget | 20 / minute / IP |
| `GET /api/try/{chainId}/{tokenId}/interface` | registry lookup and MCP discovery | shares 10 / minute / IP with Try POST |
| `POST /api/try/{chainId}/{tokenId}` | registry lookup and provider call | shares 10 / minute / IP with interface discovery |
| `GET /api/activity/{chainId}/{tokenId}` | the operator's own node credits | 15 / minute / IP |
Limits are per IP over a 60-second window and are configurable per deployment
(`VERIFY_RATE_MAX`, `TRY_RATE_MAX`, `ACTIVITY_RATE_MAX`, `RATE_WINDOW_MS`), so treat the numbers
above as this build's defaults rather than as a contract.
## The shared registry budget
This service reads the ERC-8004 registry through [8004scan](https://8004scan.io/developers). The
background sweep, registry browsing and fresh checks share the deployment's upstream allowance.
That allowance varies by deployment. Read the service's documented retry response and honor its
backoff rather than treating throttling as an agent verdict.
Two consequences you will actually feel:
- Either the local per-IP limit (`429`) or the shared upstream allowance (`503 registry-throttled`)
may be reached first, depending on the deployment's quota and concurrent usage.
- If you need many agents at once, do not loop `/api/verify`. Use `POST /api/verdicts` with up to
200 keys, which reads stored records and spends nothing. Reserve `/api/verify` for the one agent a
human is waiting on.
## The two refusals, and what each means
```
429 Too Many Requests you asked too fast. Retry-After is set.
503 registry-throttled our upstream is rate limiting us. Retry-After is set.
```
Neither is a statement about the agent you asked about. Both are temporary and both carry
`Retry-After`; honour it rather than retrying immediately, since an immediate retry consumes the
same budget it is waiting on. See [Honesty rules](/docs/honesty) for why this distinction is worth
carrying all the way into your UI.
Other statuses are documented on [API overview](/docs/api#errors).
## Caching
- Fresh verdicts are cached server-side for ten minutes by default (`VERDICT_TTL`), so a repeated
`/api/verify` for the same agent inside that window returns the same record with `cached: true`
without another upstream check. The HTTP request still counts against the per-IP verification limit.
- Within the open app, overlapping detail, metadata and verification reads for the same agent share
one request. Successful reads are reused for up to 30 seconds, with at most 100 completed entries.
Reused verdicts retain their original check timestamp and are labelled as saved evidence. Failures
are not retained as successes, so a failed read can be retried. Reloading the app clears this memory.
Task submissions and payments are outside this read cache and are never replayed by navigation.
- `/openapi.json` and `/.well-known/agent-card.json` are sent with `cache-control: public,
max-age=300`.
- The activity feed caches only a **fully clean** read for five minutes. A throttled or errored read
is never cached, so a transient failure is retryable at once rather than frozen behind a TTL.
On your side, the useful cache key is the agent key plus `formulaVersion`. Cache a verdict as long
as you like, as long as you show its age — see rule 3 of the [honesty rules](/docs/honesty).
Known agents are eligible for rechecking after 24 hours, or when their formula version becomes
obsolete. A separate queue revisits the oldest checks first. Budget, backoff and backlog determine
the actual delay; daily completion is not guaranteed. Opening an agent page may return a cached
verdict, so always display the check timestamp.
## Courtesy when calling the try relay
`POST /api/try/…` is a relay to a **third party's own server**, not to ours. Everything you send
through it costs that operator something.
- Write-shaped tool names are refused server-side, default closed. A tool qualifies as read-only
only if its name opens with a reading verb and carries no second action joined by a connective, so
`getBorrowBalance` is offered and `getOrCreateAccount` is not.
This name-based guard cannot guarantee provider behavior. A2A messages are not limited to reads.
- Verification probes default to 6 seconds; interface discovery has a 30-second deadline, and a
relayed task has a 90-second whole-operation deadline. Responses are also subject to byte caps.
Timed-out tasks are not automatically resubmitted because completion can be unknown.
- An agent may answer `402` with an x402 payment challenge. That is the agent asking to be paid, not
an error — see [Try one, then hire it](/docs/guides/hire).
## Running your own
Nothing here requires the hosted deployment. Use the Node 22 setup in the repository README and
the non-secret configuration examples supplied with the public export. Keep deployment credentials
and storage settings in the operator environment; never commit them or expose them to the browser.
---
# API overview
> One base URL, no authentication, and a hard split between endpoints that read our own records and
> endpoints that spend somebody's budget.
Base URL for this build: `https://findyouragent-verify.onrender.com`
A machine-readable description of everything below is served at
[`/openapi.json`](https://findyouragent-verify.onrender.com/openapi.json). Its `servers` block names the host you actually reached
rather than a configured one, because a configured base is one deploy away from advertising an
address that answers nothing.
## Every endpoint
### Reads that cost nothing — [details](/docs/api/reads)
| Method | Path | Returns |
| --- | --- | --- |
| `GET` | `/health` | liveness, the formula version in force, sweep stats |
| `GET` | `/api/summary` | headline counts and per-category coverage |
| `GET` | `/api/checked` | agents we hold a current verdict for, best first |
| `GET` | `/api/live` | agents holding `verified_live` under the current formula at their latest stored check |
| `GET` | `/api/search` | agents whose live endpoint served a matching capability |
| `POST` | `/api/verdicts` | stored verdicts for up to 200 agents |
| `GET` | `/api/history/{chainId}/{tokenId}` | recent checks and the day calendar |
### Calls that spend — [details](/docs/api/checks)
| Method | Path | Spends |
| --- | --- | --- |
| `GET` | `/api/agents/{chainId}/{tokenId}` | registry budget; one listing, cached for five minutes |
| `GET` | `/api/registry/agents` | registry budget; paginated BSC listing or keyword search |
| `GET` | `/api/registry/search` | registry budget; semantic search on BSC |
| `GET` | `/api/registry/stats` | registry budget; inventory counts, cached for one minute |
| `GET` | `/api/verify/{chainId}/{tokenId}` | registry budget + a probe of the agent's server |
| `GET` | `/api/agent-meta/{chainId}/{tokenId}` | registry budget |
| `GET` | `/api/activity/{chainId}/{tokenId}` | the operator's node credits |
| `GET` | `/api/try/{chainId}/{tokenId}/interface` | registry lookup and live MCP tool discovery, including reviewed `taskPresets` |
| `POST` | `/api/try/{chainId}/{tokenId}` | registry lookup and provider call; returns a dated observation and task checks for reviewed presets |
### Machine-facing surfaces — [details](/docs/machine)
| Method | Path | Returns |
| --- | --- | --- |
| `GET` | `/openapi.json` | OpenAPI 3.1 for every endpoint above |
| `GET` | `/.well-known/agent-card.json` | this service's own agent card |
| `POST` | `/mcp` | MCP over streamable HTTP, JSON-RPC 2.0 — see [MCP server](/docs/mcp) |
## Conventions
### Identifying an agent
An agent is addressed by chain id and token id. In paths they are two segments; everywhere else they
are one string:
```
56:153649 the key, used in POST /api/verdicts and every MCP tool
/api/verify/56/153649 the same agent as a path
```
Both parts are numeric and validated as such. A non-numeric segment gets `400` with
`{"error":"chainId and tokenId must be numeric"}` rather than being coerced.
Only BNB Chain (`56`) is observed today. Asking for another chain does not error everywhere. The
activity feed answers with `attribution.gate: "unsupported-chain"`, which is a named reason rather
than an empty result.
### Requests
- `GET` for everything except `POST /api/verdicts`, `POST /api/try/…` and `POST /mcp`.
- JSON bodies only, capped at 32 KB. Send `content-type: application/json`.
- No custom headers are required or read. There is nothing to authenticate.
### Responses
- JSON in UTF-8, except verification `?stream=1` and MCP responses that use server-sent events.
- Fields are tri-state: `true`, `false`, or `null`/absent for **not checked**. This is the rule
callers break most often; see [Honesty rules](/docs/honesty).
- Every verdict carries `formulaVersion` and a timestamp. Compare versions before comparing tiers.
- Timestamps are ISO 8601 in UTC.
- Amounts that come from an agent's own hire menu (`minPriceU`) are integer strings in the payment
token's smallest unit, never numbers: a price authored by the party being assessed goes nowhere
near a float.
- Try POST handled outcomes normally use HTTP `200`; read envelope `status`, `observation.outcome`,
`observation.task` and `captureComplete`. HTTP success alone is not task success. See
[observations and downloadable results](/docs/api/checks#observations-and-downloadable-results).
## Errors
| Status | Body | What it actually means |
| --- | --- | --- |
| `400` | `{"error":"chainId and tokenId must be numeric"}` | malformed path parameters |
| `400` | `{"error":"too many keys (max 200)"}` | `POST /api/verdicts` was given more than 200 keys |
| `404` | `{"error":"agent not found"}` | the registry has no such agent |
| `404` | `{"error":"agent-not-found","source":"8004scan"}` | the registry detail lookup has no such agent |
| `405` | `{"error":"method-not-allowed"}` | `GET /mcp`. The MCP server is stateless and opens no server-to-client stream; `POST` instead |
| `429` | rate limit body with `Retry-After` | you asked too fast. Not about the agent |
| `502` | `{"error":"verification-failed"}` | a check ran and could not complete |
| `502` | `{"error":"agent-timeout"}` | a request timed out; this does not establish permanent provider unavailability |
| `502` | `{"error":"interface-failed"}` / `{"error":"try-failed"}` | the relay could not complete a call to the agent |
| `502` | `{"error":"metadata-unavailable","source":"agent-metadata","retryable":true}` | the metadata document could not be read; hire-menu availability is unknown |
| `502` | `registry-unavailable`, with `source: "8004scan"` and `retryable: true` | a registry lookup could not complete |
| `502` | `registry-invalid-response`, with `source: "8004scan"` and `retryable: false` | the upstream identity, page or payload failed validation |
| `503` | `{"error":"registry-throttled"}` with `Retry-After` | **our** upstream is rate limiting us. Never a claim that an agent is broken |
Registry failures forwarded by detail, browsing, verification or metadata routes carry bounded
codes and attribution; they do not expose upstream credentials or internal error messages.
Other verification/metadata errors and uncaught relay route errors can carry a `detail` string.
Handled Try POST failures instead appear inside its HTTP `200` envelope, with a failed observation.
Inspect the failure phase before attributing a problem to the provider: an unavailable registry can
prevent a provider call from ever being attempted. See [Calls that spend](/docs/api/checks).
`402` is not an error here. It is an agent asking to be paid, and it carries that agent's own x402
challenge; see [Try one, then hire it](/docs/guides/hire).
## Where to go next
- [Reads that cost nothing](/docs/api/reads) — the endpoints to build a browse experience on.
- [Calls that spend](/docs/api/checks) — a fresh check, its streamed narration, and the relay.
- [The verdict object](/docs/api/verdict) — every field, and what it is evidence of.
---
# Reads that cost nothing
> These endpoints serve this service's own stored records. No upstream call, so they
> spend no upstream registry budget. Deployment-level limits and availability still apply.
Build your browse experience on these. Nothing here triggers an upstream check. JSON examples
illustrate the schema; sample counts and formula versions are not current measurements.
## `GET /health`
Liveness, the formula version currently in force, and the state of the background sweep.
```bash
curl -s https://findyouragent-verify.onrender.com/health
```
```json
{
"ok": true,
"formulaVersion": "0.8",
"sweep": { "queued": 812, "awaitingRecheck": 0, "swept": 4812, "considered": 9310, "callable": 74 }
}
```
The formula version is published *by the service* so that nothing else has to hardcode it. If your
integration displays a version, read it from here rather than from your own constant.
| Field | Meaning |
| --- | --- |
| `sweep.considered` | registry entries the sweep has walked past |
| `sweep.callable` | of those, how many declared an endpoint worth probing |
| `sweep.swept` | checks the sweep has actually run |
| `sweep.queued` | agents waiting to be checked |
| `sweep.awaitingRecheck` | stored verdicts computed under a superseded formula |
## `GET /api/summary`
Headline counts and per-category coverage, from stored verdicts under the current formula only.
```bash
curl -s https://findyouragent-verify.onrender.com/api/summary
```
```json
{
"checksRun": 4812,
"uniqueChecked": 1190,
"tiers": { "verified_live": 23, "active": 61, "registered": 1106 },
"awaitingRecheck": 0,
"coverage": {
"rebalancing": { "agents": 12, "served": 2, "declared": 10, "endpointProven": 3, "verifiedLive": 1 },
"grid": { "agents": 8, "served": 3, "declared": 5, "endpointProven": 4, "verifiedLive": 2 },
"yield": { "agents": 41, "served": 6, "declared": 35, "endpointProven": 6, "verifiedLive": 2 },
"health": { "agents": 5, "served": 1, "declared": 4, "endpointProven": 1, "verifiedLive": 0 }
},
"formulaVersion": "0.8",
"sweep": { "queued": 812, "awaitingRecheck": 0, "swept": 4812, "considered": 9310, "callable": 74 }
}
```
`checksRun` counts every check ever run; `uniqueChecked` counts distinct agents. The two differ by
however many times each agent has been re-checked, and quoting the first as if it were the second
would overstate coverage by an order of magnitude.
Coverage columns narrow left to right — `agents` ⊇ `endpointProven` ⊇ `verifiedLive`, with `served`
and `declared` splitting `agents` by how the placement was earned. Every judged category is listed
even when empty, because omitting the empty ones would hide the least flattering result. See
[Core concepts](/docs/concepts#coverage-and-what-each-column-counts).
## `GET /api/checked`
The default browse list: agents we hold a current verdict for, best first.
```bash
curl -s "https://findyouragent-verify.onrender.com/api/checked?limit=50"
```
| Parameter | Type | Default | Notes |
| --- | --- | --- | --- |
| `limit` | integer | `50` | clamped to 1–100 |
Rows are ordered by what was **proven**: top tier first, then agents whose endpoint answered, then by
how much evidence backs them, then by how many categories they earned. Agents at `registered` with
no proven endpoint are excluded entirely, as are verdicts computed under a superseded formula.
This ordering is the site's own judgement rather than the registry's. Sorting by "newest" put
twenty-five auto-generated nameplates on the front page, which is exactly what this project claims
to filter out.
Each row uses the shared row shape:
```json
{
"chain_id": 56,
"token_id": "153649",
"name": "Venus Protocol Agent",
"avatarUrl": "https://…/agent.png",
"hireable": true,
"minPriceU": "500000000000000000",
"servedNames": ["get_lending_positions", "get_borrow_balance"],
"tier": "verified_live",
"endpointProven": true,
"endpointKind": "mcp",
"capability": { "kind": "mcp", "noun": "tools", "declared": 12, "matched": 12, "servedCount": 14, "coverage": 1, "missing": [], "extra": [] },
"categories": [{ "category": "yield", "basis": "served" }],
"proofs": [{ "signal": "capability_integrity" }],
"latencyMs": 412,
"checkedAt": "2026-09-03T18:22:10.441Z",
"formulaVersion": "0.8"
}
```
`hireable: null` means the card could not be read — not "not hireable". `minPriceU` is `null`, never
`0`, when no offering publishes a usable price: a row must be able to say nothing rather than imply
free work.
## `GET /api/live`
Agents whose endpoint answered on the most recent check and hold `verified_live` **under the current
formula**. Up to 100 rows, newest check first, same row shape as above.
```bash
curl -s https://findyouragent-verify.onrender.com/api/live
```
A top-tier verdict earned under rules that have since been rejected is not a verdict this service
still stands behind, and this is the most prominent claim on the site, so the version filter here is
strict rather than lenient.
## `GET /api/search`
The distinguishing search: it matches capability names an endpoint **actually served** when we asked
it, not registry text.
```bash
curl -s "https://findyouragent-verify.onrender.com/api/search?q=lending"
```
| Parameter | Type | Notes |
| --- | --- | --- |
| `q` | string | tokenised on non-alphanumerics; tokens shorter than three characters, and English glue, are ignored |
```json
{
"q": "lending", "count": 3,
"agents": [{ "…": "row shape", "matchedTool": "getLendingPositions",
"matchedTerms": ["lending"], "sameToolList": 0 }]
}
```
A term matches at a **word start**, using the same normalisation that decides category placement, so
`swap` does not match `pancakeswap`. Common glue words such as `for` are removed. A query consisting
only of glue words returns no rows.
Ranking is by the **single most informative capability** a row serves that your query named — the
rarer a term is across the distinct capability sets we hold, the more a match on it counts. Ties fall
to tier, then to whether the endpoint answered, then to what the rest of that row's matches add up
to, then to how recently it was checked. Breadth is a tiebreak. The number itself
is never published; the row carries the two facts that justify its place, which are the tool that
matched and the tier.
One thing this deliberately does not do is privilege an agent's **name**. A query naming a protocol
is answered here only by what endpoints served, so `venus` finds an agent that serves
`get_venus_balance`, not one called "Venus" that serves nothing. Name matching is the registry's job,
and merging the two would be this endpoint quietly ranking on the marketing text it exists to refuse.
Agents serving an **identical** tool list collapse to one row, because they are one operator far more
often than they are independent choices. `sameToolList` is how many others were folded into that row;
in the live corpus one such fleet is 267 agents. Up to 25 rows, counted after the collapse.
`matchedTool` is the whole point: it is a name that agent's endpoint returned to us, so the match can
be inspected alongside its source and timestamp. Registry text search is available separately.
Two limits stated plainly: agents checked before this service began recording served names do not
participate — they are unknown, not "serve nothing" — and an empty `q`, or one with no token of three
characters, returns no rows rather than everything.
## `POST /api/verdicts`
Stored verdicts for a page of agents, in one request. This is the endpoint to use when rendering a
list; it never triggers a check.
```bash
curl -s https://findyouragent-verify.onrender.com/api/verdicts \
-H 'content-type: application/json' \
-d '{"keys":["56:153649","56:98765"]}'
```
| Field | Type | Notes |
| --- | --- | --- |
| `keys` | string[] | up to 200, each matching `^\d+:\d+$`. Malformed keys are dropped, not errors |
```json
{ "verdicts": { "56:153649": { "tier": "verified_live", "…": "…", "fromStore": true } } }
```
**A key we have never checked is simply absent from the response.** It is not mapped to a null row or
a zeroed score, because absence is the honest representation of "not checked". Iterate the object you
got back rather than assuming every key you sent has an entry.
Rows carry `fromStore: true` and a deliberately partial `evidence` object — the full record is one
`/api/verify` away, and re-probing every row would misrepresent how fresh this is.
More than 200 keys gets `400 {"error":"too many keys (max 200)"}`.
## `GET /api/history/{chainId}/{tokenId}`
Recent checks for one agent, plus the day calendar.
```bash
curl -s https://findyouragent-verify.onrender.com/api/history/56/153649
```
```json
{
"checks": [
{
"key": "56:153649",
"ts": "2026-09-03T18:22:10.441Z",
"tier": "verified_live",
"formulaVersion": "0.8",
"endpointProven": true,
"endpointKind": "mcp",
"latencyMs": 412,
"probe": { "declared": true, "spoke": true, "reason": null },
"proofs": ["capability_integrity"]
}
],
"uptime": {
"days": [
{ "d": "2026-09-01", "c": "o", "n": 4, "ok": 4, "ms": 380 },
{ "d": "2026-09-03", "c": "x", "n": 2, "ok": 0, "ms": null }
],
"summary": { "checkedDays": 12, "answered": 11, "unreachable": 1, "servedNothing": 0,
"firstDay": "2026-08-23", "lastDay": "2026-09-03" }
}
}
```
Checks are newest first and capped at twenty. `latencyMs` belongs to whichever probe actually proved
the endpoint, and `probe` keeps the raw facts the calendar is classified from: whether the agent
*declared* anything callable, and whether its server *spoke* at all — a 404 or a malformed body is a
reply, a timeout is silence, and the two are never coloured alike. The calendar is oldest day first, and **a day we did not check
has no entry at all** — there is deliberately no value a renderer could mistake for a reading.
| `c` | Day outcome |
| --- | --- |
| `o` | the endpoint answered |
| `?` | unreachable — a timeout, which we treat as neutral |
| `x` | answered and served nothing — the only outcome recorded against the agent |
`n` is how many checks ran that day, `ok` how many answered, `ms` the representative latency. The
denominator travels with the number because the sample is not controlled: a cache hit suppresses a
check, backoff drops ticks, and a visitor opening the page adds one.
See [Watch an agent over time](/docs/guides/monitor) for how to build on this without misreading it.
## `GET /api/escrow/{address}`
What one wallet actually did on the ERC-8183 escrow, read from the kernel's job records. A hire menu
is what an agent says it will do; this is what was opened against it and how it ended.
```bash
curl -s https://findyouragent-verify.onrender.com/api/escrow/0x1F3CBddCb9257A54d10325f900F6364C1d86BdC0
```
```json
{ "address": "0x1f3cbddcb9257a54d10325f900f6364c1d86bdc0",
"available": true, "found": true,
"record": { "jobs": 7, "released": 6, "rejected": 0, "expired": 0, "inflight": 0,
"lapsed": 1, "earnedWei": "6000000000000000000", "lastJobId": 56560 },
"range": { "topId": 56720, "floorId": 1, "jobs": 56720, "asOf": "2026-09-08T12:00:00Z",
"kernel": "0xEa4DAa3100A767e86FDed867729ae7446476EBA6", "whole": true, "unread": 0 } }
```
**Three states, and collapsing any two of them puts a claim on an agent that the chain never made.**
`available: false` means no census has been collected on this deployment — a gap in ours. `found:
false` means the range was searched and this address is not in it, which is *absent from a range*,
not zero jobs; `range` is returned with it so you can see how much of the escrow that covers.
Only a `record` is a measurement.
| Field | Meaning |
| --- | --- |
| `released` | the escrow paid out — **not** a rating, see below |
| `rejected` | the buyer rejected the delivery |
| `expired` | the job reached its expiry unsettled |
| `inflight` | open, funded or submitted, still inside its expiry |
| `lapsed` | still open on the contract but past the expiry its own buyer set |
| `earnedWei` | sum of the budgets of released jobs, exact decimal string, 18 decimals |
| `range.unread` | job ids the chain would not answer for; above zero, every count is a floor |
`released` is the contract's `completed` status, which arrives on its own once the seven-day dispute
window closes — [the exhibit job on this site](/docs/guides/hire) was disputed and released anyway.
It says money moved, not that a buyer was happy. A released job can also carry a **zero budget**, so
`released` and `earnedWei` answer different questions.
There is deliberately **no success rate**. Chain-wide only about a third of jobs on this contract
reach `completed`; the rest sit open, funded or submitted at any moment, so a percentage over jobs
created would score a provider for jobs the buyer never funded. The counts carry their own
denominator instead.
`GET /api/escrow?limit=20` returns the working providers across the whole census — ours and
everyone else's — as `{ available, rows, range, providers }`, sorted by `released`, with idle
addresses omitted. Both endpoints read a snapshot file produced out of band by `escrow-census.mjs`,
so neither spends a chain call or the registry budget.
---
# Calls that spend
> These endpoints reach outside this service: to the registry, to the chain, or to a third
> party's own server. All are rate limited per IP, because none of what they spend is ours.
Use [reads that cost nothing](/docs/api/reads) for FYA's saved checks. Use the registry routes below
for indexed registrations or a new check when a human needs it. Looping `/api/verify` over a page
of agents spends the registry budget shared with other visitors and the background sweep.
## Registry browsing and search
`GET /api/registry/agents` accepts `chainId=56`, `page` (positive integer, default 1), `limit` (1–100,
default 25), optional `search` (up to 200 characters), `sortBy` (`created_at` or `total_score`)
and `sortOrder` (`asc` or `desc`, default descending). Page, `(page - 1) * limit` and that offset
plus `limit` must be exact safe integers. There is no fixed 1,000-page cutoff.
`GET /api/registry/search` accepts `q` (1–500 characters), `chainId=56`, `page` and `limit`.
These are semantic registry matches, separate from FYA's served-capability search at `/api/search`.
Both return `data`, `source: "8004scan"` and `meta.pagination` with `page`, `limit`, `total` and
`hasMore`. FYA translates page numbers to the documented registry offsets and rejects mismatched
identities or inconsistent pagination. The browser tries keyword search when semantic search is
unavailable or empty, within one bounded request window.
`GET /api/registry/stats` takes no parameters and returns `data.chain_stats`, independently of
the visible search. Indexed inventory includes placeholders and owner-declared inactive entries.
Their presence, absence or registry score does not establish a completed task or an FYA verdict.
These routes share a 60/minute/IP limit. Page responses are cached for 30 seconds and statistics
for 60 seconds; concurrent identical reads share one upstream request. The registry key stays on
the server. `429` is FYA's request limit, `503 registry-throttled` carries the upstream wait,
and `502` identifies unavailable or invalid upstream data with `source` and `upstreamStatus`.
`registry-unavailable` is retryable; `registry-invalid-response` has `retryable: false` because
repeating a malformed response does not establish a valid listing.
An outage never becomes a successful empty page.
## `GET /api/agents/{chainId}/{tokenId}`
Reads one agent's public 8004scan listing through FYA. This uses the server's registry credentials
and shared five-minute cache, keeping the registry API key out of the browser. Only numeric chain
and token IDs are accepted; callers cannot choose an upstream host or URL.
```bash
curl -s https://findyouragent-verify.onrender.com/api/agents/56/45422
```
The listing is returned as `data`, alongside its source:
```json
{ "data": { "…": "the agent's registry listing" }, "source": "8004scan" }
```
This is registry data, including the registrant's own claims. It is not a verification verdict or
evidence of a completed task. Use [stored verdicts](/docs/api/reads) or
[`/api/verify`](/docs/api/checks) for FYA's checks.
| Status | Meaning |
| --- | --- |
| `200` | the listing, fresh or from the shared five-minute cache |
| `400` | `chainId` or `tokenId` was not numeric |
| `404` | `agent-not-found`, with `source: "8004scan"` |
| `429` | the caller exceeded the per-IP verification limit; `Retry-After` is set |
| `503` | `registry-throttled`, with `source: "8004scan"`, `retryable: true` and the validated `Retry-After` wait |
| `502` | `registry-unavailable` or `registry-invalid-response`, with `source: "8004scan"`; invalid responses have `retryable: false` |
A throttled or unavailable registry is a failed lookup, not a negative verdict about the agent.
The response contains no registry API key or upstream error text.
## `GET /api/verify/{chainId}/{tokenId}`
Runs a full verification, or serves the cached verdict if one was computed inside the TTL (ten
minutes by default).
```bash
curl -s https://findyouragent-verify.onrender.com/api/verify/56/153649
```
What one check actually does:
1. Reads the agent's registry record — name, declared endpoints, declared capabilities, wallet.
2. Fetches the agent's own identity file (its card) and, if the card claims a wallet, tries to prove
that claim against the token itself. An agent is judged on its own activity rather than its
minter's wherever that proof succeeds.
3. Probes the declared A2A endpoint and the declared MCP endpoint, in parallel.
4. Reads outbound wallet activity from a BSC node, and asks the B402 Bazaar whether settled x402
payments exist for this agent.
5. Compares what the registry says the agent offers against what the endpoint just served.
6. Checks whether the card that answered can be shown to describe *this* agent.
7. Computes a tier from the above, under the current formula version.
The response is the [verdict object](/docs/api/verdict), plus `cached`:
```json
{ "tier": "verified_live", "…": "…", "computedAt": "2026-09-03T18:22:10.441Z", "cached": false }
```
| Status | Meaning |
| --- | --- |
| `200` | a verdict, fresh or cached |
| `400` | `chainId`/`tokenId` were not numeric |
| `429` | you exceeded the per-IP limit (20/min by default). `Retry-After` is set |
| `503` | `registry-throttled`, or `identity-unavailable` with `source: "agent-identity"` and `retryable: true`. An incomplete identity read leaves the previous completed check unchanged |
| `502` | attributed `registry-unavailable` / `registry-invalid-response`, or `verification-failed` with a `detail` string; invalid registry responses are not retryable |
### `?stream=1` — the check narrated as it happens
```bash
curl -N "https://findyouragent-verify.onrender.com/api/verify/56/153649?stream=1"
```
Returns `text/event-stream`. The verifier emits frames as probe operations resolve; the last
successful frame carries the verdict. Arrival timing helps show progress but is not independent
proof that an external call happened. Inspect the observations and reproduce a request when needed.
```
data: {"step":"registry","ok":true,"name":"Venus Protocol Agent"}
data: {"step":"card","ok":true,"ownWallet":true}
data: {"step":"mcp","declared":true,"reachable":true,"servesTools":true,"toolCount":14,"latencyMs":412}
data: {"step":"a2a","declared":false,"reachable":false,"status":null,"latencyMs":null,"reason":"no endpoint declared","hasAgentCard":false,"skillsCount":null}
data: {"step":"wallet","address":"0x…","checked":true,"txCount":318}
data: {"step":"bazaar","checked":true,"listed":false,"calls30d":null}
data: {"step":"bap578","claimed":true,"tokenId":"11140","attributed":true}
data: {"step":"verdict","verdict":{"tier":"verified_live","…":"…","cached":false}}
```
| `step` | Emitted when |
| --- | --- |
| `registry` | the registry record was read |
| `card` | the agent's identity file was fetched, and whether a wallet claim was proved |
| `a2a` | the A2A probe resolved |
| `mcp` | the MCP probe resolved |
| `wallet` | wallet activity was read |
| `bazaar` | the settlement index answered |
| `bap578` | only when the card claims a BAP-578 token. `attributed` is tri-state |
| `verdict` | last frame. Carries the complete verdict |
| `error` | the check could not complete. Carries `throttled` and `message`; identity failures also carry `code: "identity-unavailable"`, `source: "agent-identity"` and `retryable: true` |
A **cached** verdict streams the `verdict` frame immediately and nothing before it. That is
deliberate: replaying invented probe steps for a check that did not happen would be a re-enactment
presented as a measurement.
## `GET /api/agent-meta/{chainId}/{tokenId}`
Registry metadata and displayable media for one agent. Spends registry budget; successful document reads are cached for 60 seconds. Add `?refresh=1` after a metadata update to discard the cached document and read it again. Concurrent reads for the same agent share one request, and refresh uses the same rate limit. Failed document reads are not cached as successes or replaced with the previous hire menu.
```bash
curl -s https://findyouragent-verify.onrender.com/api/agent-meta/56/153649
```
The response carries the registration metadata and a `media` object with a `source` that decides how
a client should treat it:
| `media.source` | Trust class | How the site renders it |
| --- | --- | --- |
| `registration` | named by the agent's own registry metadata — self-authored | ungated, same class as its avatar |
| `token` | read from the BAP-578 token the card claims | gated on the verdict's ownership check |
That distinction exists so an unattributed claim can never wear another token's skin. `media` is
`null` when nothing could be read — decoration only, and a failed read costs the picture and nothing
else.
`404 {"error":"agent not found"}` when the registry has no such agent. Registry failures use the
attributed `registry-unavailable`, `registry-invalid-response` or `registry-throttled` forms;
failed metadata document reads use `502` with `error: "metadata-unavailable"`,
`source: "agent-metadata"` and `retryable: true`. This is distinct from a failed registry lookup.
A successful response contains a non-null metadata object. An object without `services` has no
declared services; an unreadable document leaves the hire menu unknown. Media retrieval remains
best-effort and does not turn a valid metadata document into a failure.
## `GET /api/activity/{chainId}/{tokenId}`
On-chain activity, but **only** for agents whose wallet is provably their own. Spends the operator's
node credits rather than the registry budget, so it carries its own limit.
```bash
curl -s https://findyouragent-verify.onrender.com/api/activity/56/153649
```
```json
{
"key": "56:153649",
"attribution": {
"gate": "verified",
"wallet": "0x…",
"walletBasis": "the wallet derived from this agent's token via ERC-6551"
},
"coverage": { "fromBlock": 62110000, "toBlock": 62114000, "intervals": 3, "scannedThroughTs": "2026-09-03T18:30:00.000Z" },
"events": [{ "…": "one per transaction", "class": "framework" }],
"classLabels": { "framework": "…", "payment": "…" },
"sources": { "transfers": "ok", "classification": "ok" },
"cuUsed": 1420
}
```
**Read `attribution.gate` before you read `events`.** Every non-served state is a named gate with its
own sentence, so an outage or a missing wallet can never render as "no activity":
| Gate | Meaning |
| --- | --- |
| `verified` | events are attributable to this agent's own proved wallet |
| `no-verdict` | never checked, so there is no proved wallet to attach activity to |
| `no-proved-wallet` | no on-chain wallet is provably this agent's |
| `no-wallet-yet` | its token-bound wallet has not been created on-chain yet |
| `unsupported-chain` | only BNB Chain (56) is observed |
| `unconfigured` | the feed is not enabled on this deployment |
| `not-checked` | the chain could not be reached just now — about our check, not the agent |
Each event carries an origin `class`: `framework`, `framework-triggered`, `payment`, `transfer`, or
`not-checked`, with the honest sentence for each in `classLabels`. `coverage` states the exact block
window scanned, so "no events" is always bounded by a range you can see.
Only a fully clean read is cached (five minutes). A throttled or errored read is retryable
immediately rather than frozen behind a TTL.
## `GET /api/try/{chainId}/{tokenId}/interface`
Resolves the agent's declared endpoint from the registry. For MCP it discovers the current tool
list; for A2A it reports a declared message interface without proving the provider will accept it.
```bash
curl -s https://findyouragent-verify.onrender.com/api/try/56/153649/interface
```
An MCP agent:
```json
{
"kind": "mcp",
"endpoint": "https://agent.example/mcp",
"server": { "name": "venus-mcp", "version": "1.2.0" },
"tools": [{ "name": "getBorrowBalance", "title": null, "description": "…", "inputSchema": {}, "readOnly": true }],
"writeToolCount": 6,
"example": { "tool": "getProtocolStats", "args": {}, "usesSample": false, "checkedAt": "2026-09-03T18:22:10.441Z" }
}
```
An A2A agent takes free text and has no tool list:
```json
{ "kind": "a2a" }
```
`tools` contains only tools passing FYA's name-based read guard. `writeToolCount` counts the excluded
names, including ambiguous names; it does not prove every excluded tool performs a write.
The guard examines a tool name, not provider implementation. It cannot guarantee that an operator
performs no writes behind a read-shaped name. `taskPresets` contains the reviewed public fixtures
for supported agent identities, each with `id`, `version`, `tool`, `args`, `available`,
`unavailableReason` and `limitation`. A changed live schema disables the corresponding fixture.
`example` appears only when the last real check ran that zero-input tool successfully **and** the
tool is still on the live list. Nothing unvalidated is ever offered for auto-run.
`409 {"error":"agent declares no callable endpoint"}` when there is nothing to try;
`502 {"error":"the agent MCP endpoint did not answer a tools/list request"}` when the server refused.
## `POST /api/try/{chainId}/{tokenId}`
A relay to the agent's declared endpoint: read-only MCP tool calls or A2A messages. MCP names pass a
read-only guard; A2A accepts prose, so request only work you intend the provider to perform.
### Run a reviewed public task
Read `/api/try/56/45650/interface` and confirm that `pancake-bsc-lp-position` is available in
`taskPresets`, then invoke it:
```bash
curl -s https://findyouragent-verify.onrender.com/api/try/56/45650 \
-H 'content-type: application/json' \
-d '{"presetId":"pancake-bsc-lp-position"}'
```
The server owns the preset's tool and arguments, rechecks its live schema and returns the actual
input as `taskPreset {id,version,title,tool,args}`. Caller-supplied tool or arguments cannot alter a
reviewed fixture. The supported fixtures are:
| Agent key | Preset ID | What is requested |
| --- | --- | --- |
| `56:45422` | `beefy-bsc-vaults` | reported BSC vault names, assets, TVL and APY |
| `56:43129` | `venus-bsc-account-liquidity` | reported borrow limit and shortfall for a fixed public Venus CORE account |
| `56:45650` | `pancake-bsc-lp-position` | reported assets, amounts and range for a fixed public PancakeSwap V3 position |
These are point-in-time public reads. They do not deposit, rebalance, monitor an account or create a
position. Availability is established by each interface response, not by this static table.
### Invoke a generic interface
MCP — name a tool:
```bash
curl -s https://findyouragent-verify.onrender.com/api/try/56/153649 \
-H 'content-type: application/json' \
-d '{"tool":"getProtocolStats","arguments":{}}'
```
A2A — replace `` with an agent whose interface reports `kind: "a2a"`, then send prose:
```bash
curl -s "https://findyouragent-verify.onrender.com/api/try/56/" \
-H 'content-type: application/json' \
-d '{"message":"what is the current supply APY for USDT?"}'
```
| Field | Type | Notes |
| --- | --- | --- |
| `presetId` | string | Reviewed MCP task ID from `taskPresets`; overrides caller tool and arguments with the server-owned fixture |
| `tool` | string | MCP agents. Must pass the read-only check |
| `arguments` | object | MCP agents. JSON object, max 8 KB |
| `message` | string | A2A agents. Max 4000 characters |
| `payment` | string | A2A only: an encoded `X-PAYMENT` header value, non-empty and shorter than 8192 characters, passed through untouched. Not a JSON object; not forwarded for MCP |
Handled Try outcomes normally return HTTP `200`, including validation refusals and failed calls
inside the envelope. A payment challenge returns HTTP `402`. **Read the envelope's `status` and
`observation` before treating a request as successful**; `status` can be a relay refusal rather than
an upstream HTTP code. `observation.transport.status` records the upstream status when one was received.
Malformed path parameters, local rate limits and uncaught route errors can still return HTTP errors.
```json
{ "status": 200, "body": { "…": "the agent's reply" }, "endpoint": "https://agent.example/mcp", "kind": "mcp" }
```
Handled refusals in the envelope's `status`:
- `403` — the named tool is not read-only. This is enforced here and not only in the UI, because a
client can post any name it likes and this is the only place that actually stops it. A tool
qualifies only if its name opens with a reading verb and carries no second action joined by a
connective: `getBorrowBalance` yes, `getOrCreateAccount` no.
- `409` — the agent declares no valid endpoint of the kind you addressed.
- `400` — invalid `presetId`, missing or oversized `message`/`arguments`.
- `502` / `503` — a failed or throttled lookup/discovery/call. When available, `source`, `phase`,
`code`, `upstreamStatus` and `retryable` locate the failure. A registry lookup failure occurs
before any provider invocation; a transient failure at that stage can permit a later explicit
retry. Respect `retryAfterSeconds` when returned. A timeout after a tool or message was sent
leaves completion unknown; the server does not automatically resubmit a task or payment.
When an agent's declared address serves a **web page** rather than an agent interface, the relay says
so in words instead of dumping HTML at you: *"The address this agent publishes serves a web page
titled …, not an agent interface."* That is a finding about the registration, not a transport
failure, and it is one of the more common things this API will tell you.
### Observations and downloadable results
Every handled Try response includes a versioned `observation` with `runId`, protocol, endpoint,
start/finish times, latency, transport status, `captureComplete`, `outcome` and `reason`.
Protocol outcomes distinguish `response_received`, `deliverable_received`, `pending`,
`payment_required`, `error` and `unknown`. An MCP error result is not a successful response; an A2A
task marked completed without output is not a captured deliverable.
Generic calls carry `observation.task.status: "not_evaluated"`. Reviewed tasks add a task status
(`passed`, `failed`, `pending` or `incomplete`), preset/criteria versions and, when evaluated, named checks and a
limitation. Those checks test requested scope and response shape. They do not independently verify
reported prices, yields, ownership, account attribution or profitability; read each preset's exact
limitation.
The reviewed `pancake-bsc-range-assessment` task additionally checks its named position and pool facts through a separate BSC RPC at the provider's exact block. `observation.task.corroboration` retains that check's status, time, block, named checks, decoded facts and RPC request/response evidence. It must pass before the task passes. RPC unavailability remains `incomplete`; a factual contradiction fails. The provider response is retained in both cases. Observation latency describes the provider relay; corroboration carries its own check time. No costs, profitability, approvals or continuous execution are certified by this task.
`captureComplete: true` means FYA captured the protocol response rather than a shortened display.
It does not mean the provider returned all relevant real-world data or that its answer is correct.
A failed capture remains explicit. The HTTP status, protocol outcome, task checks and capture flag
are separate facts.
The browser's **Download result** saves `schemaVersion: 1`, `recordType: "fya-observed-agent-result"`,
agent identity and endpoint, exact request, observation and captured response as JSON. Request
headers and wallet payment signatures are excluded. `response.paymentReceipt` preserves the decoded
provider receipt, or `null` when none was returned. That metadata requires separate on-chain
verification; it does not pass task checks. Older exports omitted this field even when a receipt
may have been returned. This file is not provider-signed or a settlement receipt.
A failed rerun preserves earlier results with their original observation times; it does not
make them fresh. See the [evidence guide](/docs/evidence) for published records and reproduction.
This service never signs or holds funds. For A2A messages, an `X-PAYMENT` header produced by your wallet passes
through untouched, and any settlement receipt the agent returns comes back as `paymentReceipt` —
decoded server-side because browsers usually cannot read that header cross-origin. See
[Try one, then hire it](/docs/guides/hire).
MCP payment forwarding is not supported. The browser wallet flow accepts x402 version 1 EIP-3009
challenges (`exact` or `eip3009`) on BSC for the configured 18-decimal `$U` token and signing domain
only; an unsupported asset must not be displayed as `$U`.
---
# The verdict object
> One record per agent per check. `tier` is a summary of the fields under it, and the fields are the
> part worth reading — several of them exist specifically to say what the verdict does **not** claim.
A verdict comes back whole from `GET /api/verify/{chainId}/{tokenId}` and in a deliberately partial
form from `POST /api/verdicts` and the browse endpoints, where the full evidence is one request away.
This page documents the whole thing.
## Identity and provenance
| Field | Type | Notes |
| --- | --- | --- |
| `agentId` | string | the registry's own id, falling back to the `chainId:tokenId` key |
| `name` | string \| null | as registered. `null` when the registry has none |
| `avatarUrl` | string \| null | a poster image the registration itself names, byte-verified as an image at check time. A 3D-only agent yields `null` here rather than handing a `.glb` to an `
` tag |
| `formulaVersion` | string | the rules this verdict was computed under. **Compare this before comparing tiers** |
| `computedAt` | ISO 8601 | when this check ran. On stored rows the same instant is called `checkedAt` |
| `cached` | boolean | on `/api/verify` only: whether this came from the cache rather than a fresh check |
| `fromStore` | `true` | on stored rows only: this came from our records, not a fresh probe |
## The tier and what carried it
| Field | Type | Notes |
| --- | --- | --- |
| `tier` | `"verified_live"` \| `"active"` \| `"registered"` | see [Core concepts](/docs/concepts#the-three-tiers) |
| `endpointProven` | boolean | an A2A card with substance, or an MCP server that completed `initialize` and returned a non-empty `tools/list` |
| `endpointKind` | `"mcp"` \| `"a2a"` \| `null` | which protocol actually proved it. `null` when neither did |
| `proofs` | array | every signal found, each `{signal, detail}` |
| `corroboratedSignals` | string[] | the subset of `proofs` that corroborate the **endpoint** |
`proofs` and `corroboratedSignals` are not the same list, and the difference is the formula's central
judgement. `wallet_activity` can appear in `proofs` and never in `corroboratedSignals`, because it
describes an *address* while the top tier is a claim about an *endpoint*.
```json
"proofs": [
{ "signal": "capability_integrity", "detail": "serves all 12 tools its registry metadata advertises" },
{ "signal": "wallet_activity", "detail": "318 transactions from agent wallet (threshold 8: wallet owns 2 agents, mint cost discounted)" }
],
"corroboratedSignals": ["capability_integrity"]
```
| Signal | Corroborates the endpoint? |
| --- | --- |
| `capability_integrity` | yes, for this formula — two publisher-controlled records agree; not independent validation |
| `b402_settlement` | yes — payments settled against it |
| `registry_feedback` | yes — on-chain feedback was submitted about it |
| `wallet_activity` | no — reported for context only |
On stored rows `proofs` is flattened to `[{ "signal": "capability_integrity" }]` without the detail
string. The detail is regenerated by a fresh check.
## `capability` — declared against served
`null` when the agent declares no capabilities at all, which is common and is not a failure.
```json
"capability": {
"kind": "mcp",
"noun": "tools",
"declared": 37,
"matched": 6,
"servedCount": 14,
"coverage": 0.162,
"missing": ["executeSwap", "getPortfolio"],
"extra": ["healthCheck"]
}
```
| Field | Notes |
| --- | --- |
| `kind` / `noun` | `mcp`/`tools` or `a2a`/`skills`. Both compare listed capability names; neither establishes correct execution |
| `declared` | how many capabilities its registry metadata advertises |
| `matched` | **the intersection** — how many of those the live endpoint actually served |
| `servedCount` | how many the endpoint offers in total. Context, never the headline |
| `coverage` | `matched / declared` |
| `missing` | declared but not served, first 20. Published rather than softened |
| `extra` | served but never declared, first 20. Not a fault — it means the registry record understates the agent |
`matched` counts the intersection; `servedCount` can also include unrelated names.
The `capability_integrity` proof requires `missing` to be empty **and** `matched >= 3`. A ratio
threshold would reward small denominators, and a floor of three stops a one-skill declaration from
earning corroboration for keeping a single trivial promise.
## `subject` — is this card about this agent?
```json
"subject": { "verified": true, "how": "the card was served from a url addressing this agent" }
```
A hard bar on the top tier rather than an entry in `proofs`. A shared fleet endpoint serves a valid,
healthy card describing the service, and every identity pointing at it would otherwise inherit that
liveness for free — a failure the capability comparison is structurally blind to, since a fleet card
matches itself perfectly.
`how` is a sentence, and the failing ones are as informative as the passing ones: *"the served card
could not be shown to be this agent's own"*, *"no card was served"*.
Checked for A2A only. An MCP server is addressed by its own endpoint and has no fleet-card
equivalent to be confused with. `null` when the question did not arise.
## `categories`
```json
"categories": [
{ "category": "yield", "basis": "served" },
{ "category": "health", "basis": "declared" }
]
```
`basis` always travels with the placement. `served` means the live endpoint listed a matching
capability when asked; `declared` means only the registry metadata or the card says so. The judged
categories are `rebalancing`, `grid`, `yield` and `health`; an agent that publishes no capability is
placed in nothing.
## `servedNames`
The capability names the live endpoint actually served, capped at 120. This is what
[`/api/search`](/docs/api/reads#get-api-search) matches against, which is why a search hit can name
the tool that matched.
**Absent means not-yet-rechecked, never "serves nothing."** Agents checked before this field existed
simply do not participate in search rather than ranking last.
## Hiring
| Field | Type | Notes |
| --- | --- | --- |
| `hireable` | boolean \| null | whether the agent's own identity file publishes an ERC-8183 menu naming a BNB Chain (`eip155:56`) provider. `null` when the card could not be read — unknown, not "no" |
| `minPriceU` | string \| null | the cheapest **priced** offering on that menu, as an integer string in the payment token's smallest unit. `null`, never `0`, when no offering names a usable price |
Prices are authored by the party being assessed, so anything that is not a clean positive integer is
ignored rather than guessed at or coerced — and `minPriceU` stays a string all the way to the screen
rather than passing through a float.
## `bap578`
Present when the agent's card claims a BAP-578 token; `null` otherwise.
| Field | Notes |
| --- | --- |
| `collection` / `tokenId` | the token the card claims |
| `ownershipVerified` | tri-state. `true` when the claim was proved on-chain, `false` when it was disproved, `null` when it could not be checked |
| `logicAddress` | the agent's logic contract, when readable |
| `totalActions` / `totalTrades` | reported metrics — **only** when the contract actually reported them, `null` otherwise |
`ownershipVerified` travels with every stored row on purpose. Without it, a replayed record is a
token id and a trade count with nothing saying whether they were ever shown to belong to this agent,
and the numbers would read as established the moment they load.
The [activity feed](/docs/api/checks#get-api-activity-chainid-tokenid) is gated on this: no proved
wallet, no attributed events.
## `evidence`
The raw observations the tier was computed from. Whole on a fresh check; on stored rows only
`evidence.endpoint.latencyMs` survives, because keeping the rest would bloat the replay the store
does on every boot.
### `evidence.endpoint` — the A2A probe
| Field | Notes |
| --- | --- |
| `declared` | whether the agent declared an A2A endpoint at all |
| `reachable`, `status`, `latencyMs` | what the call did |
| `hasAgentCard` | true only for a card with substance: a protocol version, a callable url, additional interfaces, or real skills. A bare `name` is not a card |
| `skillsCount`, `skillIds` | what the card published |
| `reason` | `no-endpoint`, `invalid-url`, `http-error`, `not-json`, `timeout`, `unreachable` |
### `evidence.mcp` — the MCP probe
| Field | Notes |
| --- | --- |
| `declared`, `reachable`, `status`, `latencyMs` | as above |
| `servesTools` | `initialize` completed **and** `tools/list` returned at least one tool |
| `toolCount`, `toolIds` | normalised names, used for the capability comparison and for search |
| `protocolVersion`, `serverName` | what the server said about itself |
| `reason` | adds `initialize-rejected` and `tools-list-rejected` to the list above |
`reason` is worth surfacing in a UI. `initialize-rejected` and `not-json` are findings about a
registration; `timeout` is not distinguishable from our own egress and is treated as neutral
everywhere in this system.
### `evidence.wallet`
`{ checked, address, txCount, balanceWei }`. `checked: false` means the node did not answer — the
formula then emits no wallet proof rather than assuming zero.
`agentsOwned` is asked only when falling back to the registrant's address, since a proved ERC-6551
account belongs to one token by construction. When it is unknown, **no wallet proof is emitted**;
an unavailable ownership count cannot establish activity beyond minting.
### `evidence.bazaar`
`{ listed, checked, resourceCount, calls30d, uniquePayers }` from the B402 Bazaar. A listing exists
only because x402 payments settled, which is why it corroborates. `checked: false` distinguishes "we
asked and it is not listed" from "we could not ask".
### `evidence.registry`
What 8004scan holds: `feedbackCount`, `healthScore`, `isEndpointVerified`,
`endpointVerificationError`, `protocols`, `x402Supported`, and `observedMcp` — that registry's own
last observation of the agent's MCP endpoint, with its own timestamp. Their observation and ours are
kept separate and dated separately, because they are two different measurements and merging them
would erase whose finding is whose.
---
# MCP server
> Four public, stateless, read-only tools over streamable HTTP. They serve stored evidence without
> spending the upstream registry budget.
Endpoint: `https://findyouragent-verify.onrender.com/mcp` · Transport: streamable HTTP · Protocol revision: `2025-06-18`
## Connecting
```json
{
"mcpServers": {
"findyouragent": { "url": "https://findyouragent-verify.onrender.com/mcp" }
}
}
```
No key, no session, no headers required. The server is **stateless**: it issues no session id, so a
client can initialize and call in any order without holding state, and a restart mid-conversation
cannot invalidate a session someone is using.
By hand:
```bash
curl -s https://findyouragent-verify.onrender.com/mcp \
-H 'content-type: application/json' \
-d '{"jsonrpc":"2.0","id":1,"method":"tools/list","params":{}}'
```
`GET /mcp` returns `405`. This server opens no server-to-client stream, and saying so is more useful
than holding a connection that will never carry anything.
## The four tools
### `search_agents`
Finds agents whose endpoint **actually served** a matching capability when we last called it — not
what their registration claims.
```json
{ "name": "search_agents", "arguments": { "task": "check my venus health factor", "limit": 10 } }
```
| Argument | Type | Notes |
| --- | --- | --- |
| `task` | string, required | what you need done. Tokens under three characters, and English glue, are ignored |
| `limit` | integer | 1–25, default 10 |
Each result carries the `key` to pass back to `get_verdict`, a `page` a person can be sent to, and
`matchedTool` — the name that agent's endpoint returned to us. The result also carries its own
`basis` string saying exactly that, so a model reading it in a loop cannot lose the provenance on the
way to a summary.
An agent absent from these results may simply never have been checked. That is a gap in our
coverage, not a finding about the agent.
### `get_verdict`
```json
{ "name": "get_verdict", "arguments": { "key": "56:153649" } }
```
Returns the stored verdict, the agent's page url, and — when we have never checked it — `verdict:
null` with a note saying so in words:
```json
{ "key": "56:98765", "page": "https://findyouragent.xyz/#/agent/56/98765", "verdict": null,
"note": "we have never checked this agent. That is a gap in our coverage, not a finding about the agent." }
```
For a check run **right now**, call `GET /api/verify/{chainId}/{tokenId}` over HTTP instead. That
one is rate limited, because it spends a shared registry budget and a human is usually waiting for
it.
### `get_history`
```json
{ "name": "get_history", "arguments": { "key": "56:153649" } }
```
Recent checks plus the day calendar. A day with no entry is a day we did not check: our sampling gap,
never that agent's downtime. Only a day where their server answered and served nothing is recorded
as a failure; a timeout is neutral, because from one vantage point it cannot be told apart from our
own egress.
### `coverage`
```json
{ "name": "coverage", "arguments": {} }
```
Headline counts and per-category coverage, plus the formula version used. `agents` contains the
`endpointProven` subset, which contains `verifiedLive`. Separately, `served` and `declared` split
category placement by its basis. A verified agent can retain a declaration-based category.
The result carries its own note: counts include only verdicts computed under the current formula
version; older ones are withdrawn until rechecked.
## Why none of these reach the registry
Every tool here reads this service's own stored records and nothing else. That is a deliberate
design decision rather than a limitation.
MCP tools may be called repeatedly by software, so they read stored records and spend no upstream
registry budget. New checks use the rate-limited HTTP verification route. Deployment-level request
limits and availability still apply. Every result states when it was observed so callers can
distinguish stored evidence from a new check.
## Errors
A tool error is reported **inside the result**, not as a JSON-RPC error:
```json
{ "content": [{ "type": "text", "text": "key must look like \"56:153649\"" }], "isError": true }
```
The call reached us and we answered; the caller's model should see what went wrong rather than a
transport failure it cannot act on. Genuine protocol problems — an unknown tool, an unknown method —
do return JSON-RPC errors (`-32602`, `-32601`).
Every successful call returns both `content` (the JSON as text) and `structuredContent` (the same
object), so clients that support either shape get the typed version.
## The card and the tool list cannot drift
This service's [agent card](https://findyouragent-verify.onrender.com/.well-known/agent-card.json) advertises a skill per tool, and
both the card's skill list and the MCP `tools/list` response are built from the same table in the
source.
That is not tidiness. This site marks agents down for declaring an interface they do not serve, and
a hand-written card that drifted from the real tool list would make exactly that charge true of us.
The drift is impossible by construction, and a test fails if someone makes it possible again.
The card also deliberately does **not** declare an A2A `url` or a `preferredTransport`: this service
does not answer A2A `message/send`, and a card that said otherwise would be precisely the
registration this site marks down elsewhere.
---
# Machine-readable surfaces
> The interactive app uses hash routes. Static documentation and evidence links expose the product,
> observations and API without requiring a reader to execute the app.
Start with [About Find Your Agent](/docs/about), then inspect the
[evidence guide](/docs/evidence) and [JSON index](https://findyouragent.xyz/evidence/index.json).
The [open marketplace scope](/docs/about#an-open-marketplace-for-bnb-chain-agents) explains how FYA serves compatible providers across the ecosystem, including competing teams, under the same published verdict formula. [Compatibility limits](/docs/concepts#bnb-agent-compatibility) distinguish generic interfaces from provider-specific presets and supported payment configurations.
## On the service
| File | What it is |
| --- | --- |
| [`/openapi.json`](https://findyouragent-verify.onrender.com/openapi.json) | OpenAPI 3.1 for every endpoint, including the throttle semantics |
| [`/.well-known/agent-card.json`](https://findyouragent-verify.onrender.com/.well-known/agent-card.json) | this service's own agent card |
| `POST /mcp` | an MCP server — see [MCP server](/docs/mcp) |
| [`/health`](https://findyouragent-verify.onrender.com/health) | liveness and the formula version currently in force |
### `/openapi.json`
The `servers` block names **the host you actually reached**, derived from the request, rather than a
configured base — a configured base is one deploy away from advertising an address that answers
nothing.
The description carries the three semantics callers get wrong, so a generated client's own
documentation carries them too:
1. Unknown is `null`, never `0`.
2. Every verdict carries `formulaVersion`, and older ones are withdrawn from headline counts until
rechecked.
3. A `503` is a wait, not a verdict.
Cached for five minutes.
### `/.well-known/agent-card.json`
This service described as an agent, because it is one.
```json
{
"name": "findyouragent",
"formulaVersion": "0.8",
"services": { "mcp": { "endpoint": "https://findyouragent-verify.onrender.com/mcp", "transport": "streamable-http" } },
"interfaces": [
{ "kind": "mcp", "endpoint": "https://findyouragent-verify.onrender.com/mcp", "transport": "streamable-http", "protocolVersion": "2025-06-18" },
{ "kind": "http-json", "endpoint": "https://findyouragent-verify.onrender.com/api", "openapi": "https://findyouragent-verify.onrender.com/openapi.json" }
],
"capabilities": { "streaming": true, "authentication": "none", "pricing": "none" },
"skills": [{ "id": "search_agents", "…": "…" }],
"semantics": { "unknown": "…", "throttle": "…", "freshness": "…" }
}
```
The card above illustrates the schema; read the live card for the current formula version.
Two details are deliberate:
- **`services.mcp` uses the shape our own registry reader expects.** If this service were ever
registered on-chain, our own sweep could probe it under exactly the same rules as anyone else.
- **No A2A `url`, no `preferredTransport`.** This service does not answer A2A `message/send`, and a
card claiming otherwise is the misconfiguration this site marks other agents down for.
The `skills` array is generated from the same table that produces the MCP tool list, so the card
cannot advertise a capability the server does not serve.
## On the site
| File | What it is |
| --- | --- |
| [`/llms.txt`](https://findyouragent.xyz/llms.txt) | an index of the API for whoever is reading rather than browsing |
| [`/llms-full.txt`](https://findyouragent.xyz/llms-full.txt) | every page of this documentation, concatenated |
| [`/docs/about`](https://findyouragent.xyz/docs/about) | product scope, demonstration steps and evidence links |
| [`/evidence/index.json`](https://findyouragent.xyz/evidence/index.json) | dated records with provenance and limitations |
| [`/ai.txt`](https://findyouragent.xyz/ai.txt) | what may be reused, and what was never ours to license |
| [`/robots.txt`](https://findyouragent.xyz/robots.txt) | crawling is allowed; the file says what a crawler will actually get |
`llms.txt` is **generated at build time** against the same `VITE_VERIFY_API` as the app. A build
without that variable has no backend for registry browsing, saved checks or task calls; static
documentation remains readable. A configured URL is a declared destination, not an availability
check. Test the deployed service separately.
## These pages
Every documentation page is served three ways:
| Form | URL | For |
| --- | --- | --- |
| HTML | `/docs/quickstart` | people |
| Markdown | `/docs/quickstart.md` | anything reading rather than browsing |
| Everything at once | [`/llms-full.txt`](https://findyouragent.xyz/llms-full.txt) | a model that wants the whole corpus in one fetch |
They are static HTML rendered at build time from markdown in the repository, with no client-side
routing and no data fetching. That is not a style preference: this project publishes the fact that
its app cannot be read without a browser, and documentation with the same defect would be the same
finding wearing a helpful face.
Nothing on a documentation page requires JavaScript. The search box is the only scripted element,
it is created by script rather than written into the markup, and a reader without JavaScript is
therefore never shown a box that does nothing.
## Reuse
The verdicts, probe records, uptime calendar, coverage counts and this documentation are ours, and
you may reuse them with attribution to [https://findyouragent.xyz](https://findyouragent.xyz). Agent names, cards, images and registry
records belong to the parties that published them on-chain — we republish those; we do not license
them. Neither is anything an agent returned through the try relay, which is that agent's output and
not ours.
Full terms, and the two ways a copied verdict goes wrong, are in [Reuse this data](/docs/guides/reuse).
---
# Pick an agent that can do the job
> The useful question is not "which agents exist for this?" — the registry answers that with tens of
> thousands of names. It is "which of them answered a request, and what did they actually offer when
> asked?"
This guide builds a picker end to end: find candidates, rank them on evidence, and present the ones
you know nothing about without libelling them.
## 1. Search what endpoints served, not what registrations claim
```bash
curl -s "https://findyouragent-verify.onrender.com/api/search?q=liquidity+rebalance"
```
This search matches capability names returned by endpoints at check time. Registry search is also
available for discovery from names and descriptions. A listed capability is a candidate for a task
test, not proof that the task will succeed.
```json
{
"q": "liquidity rebalance",
"count": 2,
"agents": [
{ "chain_id": 56, "token_id": "153649", "name": "…", "tier": "verified_live",
"matchedTool": "rebalancePosition", "endpointKind": "mcp",
"categories": [{ "category": "rebalancing", "basis": "served" }],
"checkedAt": "2026-09-03T18:22:10.441Z", "formulaVersion": "0.8" }
]
}
```
Show `matchedTool` in your UI. It is the difference between "we think this agent does X" and "this
agent's own server listed X when we asked it, at this time" — and it lets your user check the match
instead of trusting your ranking.
Tokens under three characters are ignored, so `q=fi` finds nothing. Prefer whole words from the
domain: `lending`, `rebalance`, `health factor`.
## 2. Or browse by category, and read the basis
```bash
curl -s "https://findyouragent-verify.onrender.com/api/checked?limit=50"
```
Rows come back ordered by what was proven, not by recency: top tier first, then a proven endpoint,
then weight of evidence. Each row's `categories` entry carries a `basis`:
- `served` — the live endpoint listed a matching capability when asked.
- `declared` — only the registry metadata or the card says so.
Those are different claims and a picker should not flatten them. A `declared` placement is a
starting point for a check; a `served` placement is a finding.
## 3. Rank on evidence, not on the tier alone
The tier is a summary. If you rank on it alone you inherit our judgement wholesale; the fields under
it let you form your own. A reasonable ordering for "who should I actually try":
1. `endpointProven && corroboratedSignals.length > 0` — the endpoint answered and a qualifying
signal was recorded. Inspect which one; capability consistency may be publisher-controlled.
2. When `capability.declared > 0`, `capability.missing.length === 0` — the listed capabilities match its declarations. This does not test their execution.
3. Freshness: how old is `checkedAt`?
4. `latencyMs`, if responsiveness matters to your use case.
5. `hireable === true` and a `minPriceU` you can afford, if you intend to pay.
What not to rank on:
- **`proofs.length` alone.** `wallet_activity` is in there, and it describes an address rather than
an endpoint. A busy minter's wallet can carry a nameplate to the top of a naive sort. Use
`corroboratedSignals` if you want a count that means something.
- **`capability.servedCount`.** It answers "how many tools does this server offer", not "how many of
its promises does it keep". `matched` against `declared` is the honest pair.
## 4. Present unchecked agents honestly
This is the part most integrations get wrong, and it is not a detail — most of the registry is
unchecked.
```js
const res = await fetch(`${API}/api/verdicts`, {
method: 'POST',
headers: { 'content-type': 'application/json' },
body: JSON.stringify({ keys: pageOfAgents.map((a) => `${a.chainId}:${a.tokenId}`) }),
});
const { verdicts } = await res.json();
for (const agent of pageOfAgents) {
const verdict = verdicts[`${agent.chainId}:${agent.tokenId}`];
// A key we have never checked is ABSENT. Not null-scored, not zero, not last.
agent.status = verdict ? verdict.tier : 'unchecked';
}
```
Render `unchecked` as words — *not checked yet*, a dash, an empty cell. What it must never become is
a `0` sitting in a column of scores, where a reader will compare it against a measurement. See
[Honesty rules](/docs/honesty).
Up to 200 keys per request, and it never triggers a check, so a paged list costs the shared registry
budget nothing.
## 5. Check the one the user picked, live
When a person has narrowed it down to one agent and is about to act, spend the budget:
```bash
curl -N "https://findyouragent-verify.onrender.com/api/verify/56/153649?stream=1"
```
The streamed form narrates each probe as it resolves, which is worth showing rather than hiding
behind a spinner — the ordering and the jitter are what distinguish a real check from a progress
animation. A cached verdict streams one frame immediately and no invented steps.
Handle two refusals distinctly:
- `429` — you asked too fast. Back off, honour `Retry-After`.
- `503 registry-throttled` — our upstream is limiting us. **Say "check unavailable, try again
shortly", never "verification failed"**, which reads as a claim about the agent.
## 6. Then try it before recommending it
A verdict records whether an endpoint answered and what it listed. Missing declarations, a failed
probe and capability mismatches remain visible. Try a useful task and inspect its output before
recommending an agent. [Try one, then hire it](/docs/guides/hire) covers reviewed fixtures, the
name-based MCP guard and the limits of task checks.
## A note on absence
An absent search result can mean the agent is unchecked, has no served matching capability, or was
folded into a group sharing the same tool list. It is not a negative quality verdict.
`uniqueChecked` in [`/api/summary`](/docs/api/reads) gives the checked population; compare it with
available registry inventory before describing coverage.
---
# Try one, then hire it
> Inspect an agent's interface, try a supported call, then choose a payment or escrow flow where offered.
## Step 1: find out what it will accept
```bash
curl -s https://findyouragent-verify.onrender.com/api/try/56/153649/interface
```
The interface resolves the registered endpoint and distinguishes two shapes:
- **MCP** — named operations with typed arguments. You get the live tool list.
- **A2A** — a declared free-text interface. You get `{"kind":"a2a"}`; this alone does not establish that the provider will accept a message.
```json
{
"kind": "mcp",
"endpoint": "https://agent.example/mcp",
"tools": [{ "name": "getBorrowBalance", "description": "…", "inputSchema": {}, "readOnly": true }],
"writeToolCount": 6,
"example": { "tool": "getProtocolStats", "args": {}, "usesSample": false, "checkedAt": "2026-09-03T18:22:10.441Z" }
}
```
`tools` lists only tools passing FYA's name-based read guard, and `writeToolCount` says how many were withheld. Both halves
are published on purpose: hiding the write tools would misrepresent what the agent does, and showing
them as callable would be worse.
Excluded names include ambiguous ones; the count is not proof that every excluded tool writes state.
For supported agents, the same response includes `taskPresets`: reviewed tasks with their exact
inputs, live availability and limitations. For example, discover
`/api/try/56/45650/interface`, then run an available public position read:
```bash
curl -s https://findyouragent-verify.onrender.com/api/try/56/45650 \
-H 'content-type: application/json' \
-d '{"presetId":"pancake-bsc-lp-position"}'
```
The server fixes the tool and arguments and checks the live schema again before calling. The
browser exposes the same task and a **Download result** action after a response. Inspect the exact
request, original observation time, full captured response and task checks. A passed result means
the stated scope/shape checks passed; it is not independent validation of provider data. See
[reviewed tasks and result semantics](/docs/api/checks#run-a-reviewed-public-task).
## Step 2: call a read-only MCP tool
```bash
curl -s https://findyouragent-verify.onrender.com/api/try/56/153649 \
-H 'content-type: application/json' \
-d '{"tool":"getProtocolStats","arguments":{}}'
```
The response wraps the agent's own reply, with the agent's status inside the body and the endpoint
that was actually called:
```json
{ "status": 200, "body": { "…": "the agent's own reply" }, "endpoint": "https://agent.example/mcp", "kind": "mcp" }
```
### Why only reads
Some servers mix reads
with writes — one lending agent serves `getBorrowBalance` next to `borrow`, `repay` and `mintToken`.
So the decision is made by name and is **default-closed**: a tool is offered only if it opens with a
reading verb and carries no second action joined by a connective. `getBorrowBalance` passes;
`getOrCreateAssociatedTokenAccount` does not.
This occasionally hides a harmless tool. That is the correct direction to be wrong in: the cost of
hiding a read is a missing demo, and the cost of exposing a write is a stranger's button doing
something on someone's behalf.
The check is enforced server-side, not only in the UI, because a client can post any name it likes
and this is the only place that stops a write-shaped name. Posting one produces envelope
`status: 403` inside HTTP `200`. A provider can still implement a write behind a read-shaped name;
this guard cannot guarantee its behavior. A2A prose has no equivalent read-only restriction.
### When the reply is not what you expected
If an agent's declared address serves a **web page**, the relay says so in words rather than dumping
HTML at you:
> The address this agent publishes serves a web page titled "…", not an agent interface. A browser
> gets a website here; anything speaking A2A gets nothing it can use.
That is a finding about the registration, not a transport failure — and it is one of the more common
outcomes on this registry.
Try normally returns HTTP `200` for handled outcomes. Read envelope `status` and `observation`,
including task checks and capture completeness; HTTP `200` is not evidence of success. Pending,
payment-required, failed and unclassified results stay distinct. A failed rerun keeps earlier
results with their original timestamps. Result JSON is an FYA observation, not a provider-signed
attestation or payment receipt.
## Step 3: pay per call, with x402
The relay supports x402 payment forwarding for **A2A messages**. It does not forward payments for
MCP tool calls. The browser wallet flow supports x402 version 1 EIP-3009 payments (`exact` or
`eip3009`) on BSC with the configured 18-decimal `$U` token and signing domain only. Other network,
scheme or asset requirements must not be relabeled as
`$U`; use an appropriate client if the UI marks a challenge unsupported.
An A2A agent that wants payment answers `402` with its own challenge instead of a result:
```json
{ "status": 402, "body": { "accepts": [{ "scheme": "exact", "network": "bsc", "…": "…" }] } }
```
That is the agent asking to be paid, not an error. The flow:
1. Your wallet signs a payment authorisation for the challenge it received.
2. You post the same request again with the encoded header value in `payment`.
3. The relay forwards it as `X-PAYMENT`, untouched.
```bash
curl -s "https://findyouragent-verify.onrender.com/api/try/56/" \
-H 'content-type: application/json' \
-d '{"message":"what is the current supply APY for USDT?","payment":""}'
```
Replace `` with an agent whose interface response is `{"kind":"a2a"}` and repeat the
exact message that produced the challenge. A payment field does not enable paid MCP.
**This service never signs, holds, or custodies funds.** For A2A, the header your wallet produced passes
through as-is. If the agent returns a settlement receipt it comes back as `paymentReceipt`, decoded
server-side — browsers usually cannot read that header cross-origin, but a server relay can.
**Download result** retains this provider-reported metadata as `response.paymentReceipt`, or `null`
when unavailable. Check its transaction on-chain before treating payment as settled; a receipt does
not establish the quality or correctness of the answer. Earlier downloads omitted the receipt field.
Settled x402 payments are also what makes an agent visible to the B402 Bazaar, which is why
`b402_settlement` counts as corroboration in a [verdict](/docs/api/verdict): a listing exists only
because payments settled.
## Step 4: or hire it with escrow, via ERC-8183
Pay-per-call suits a question. A *job* — something with a deliverable, a budget and a dispute
window — is what ERC-8183 escrow is for.
### The gate
An agent is hireable only if its own identity file publishes an ERC-8183 service entry naming a BNB
Chain provider:
```json
"services": [
{ "name": "erc8183", "endpoint": "eip155:56/0x…", "offerings": [{ "priceU": "1000000000000000000", "…": "…" }] }
]
```
The verdict carries the result of that read so a browse row can offer "hire" only where it is
genuinely on offer — a hire button leading to "not hireable" is a dead end dressed as an action:
| Field | Meaning |
| --- | --- |
| `hireable: true` | the card publishes a menu naming an `eip155:56` provider |
| `hireable: false` | it does not |
| `hireable: null` | the card could not be read. **Unknown, not "no"** |
| `minPriceU` | cheapest priced offering, an integer string in the token's smallest unit. `null`, never `0`, when nothing names a price |
`$U` carries 18 decimals, so `"1000000000000000000"` is 1 `$U`. It stays a string end to end; a price
authored by the party being assessed goes nowhere near a float.
### The sequence
Escrow runs on-chain from the user's own wallet — this service is not in the path. The order is
load-bearing:
```
approve $U → createJob → registerJob(policy) → setBudget → fund
```
| Contract | Address on BSC |
| --- | --- |
| kernel | `0xEa4DAa3100A767e86FDed867729ae7446476EBA6` |
| router | `0x51895229E12F9876011789B04f8698af06cCD6DA` |
| policy | `0x9C01845705b3078Aa2e8cfF7520a6376FD766dE5` |
| `$U` token | `0xcE24439F2D9C6a2289F741120FE202248B666666` |
Three constraints that are easy to miss and quiet when you get them wrong:
- **Minimum budget of 1 `$U`.** Providers skip jobs below it, so an underfunded job is never worked
rather than rejected.
- **Expiry must exceed the dispute window.** The dispute window is seven days; an expiry inside it
produces a job that cannot complete. Twelve days is the working default.
- **Descriptions are capped at 1000 characters**, because provider runtimes cap what they read.
A job moves through `open → funded → submitted → completed`, with `rejected` and `expired` as the
other terminal states. After submission the policy contract's dispute window applies. Available
settlement, dispute and refund actions depend on the job state and contract policy; refunds may
require a claim transaction.
The reference implementation of all of this is `web/src/lib/erc8183.js` in the repository, including
the transaction-error explanations, which are worth reading before writing your own.
### What the escrow exhibit demonstrates
The site's exhibit is third-party history for job `56620` on this contract. It was disputed and
later released. It is not evidence that findyouragent completed its own hire flow or that a useful
deliverable was accepted. Release means a contract payout, not a quality rating.
## What a verdict does and does not tell you before you pay
It records whether an endpoint answered, what could be read, capability consistency, available
identity evidence and the observation time. A verdict can also record no callable endpoint or no
reply. Inspect its fields rather than treating the existence of a verdict as a positive result.
It does not tell you the agent is good at the job, that it will still be up in an hour, or that its
price is fair. Those are questions for a try call, the [uptime calendar](/docs/guides/monitor), and
your own judgement — in that order.
---
# Watch an agent over time
> A check records one observation. A calendar shows the observations over time, with gaps for days
> when FYA did not check. It is sampled history, not continuous uptime monitoring.
## The shape of the data
```bash
curl -s https://findyouragent-verify.onrender.com/api/history/56/153649
```
```json
{
"checks": [{ "ts": "2026-09-03T18:22:10.441Z", "tier": "verified_live", "latencyMs": 412,
"probe": { "declared": true, "spoke": true, "reason": null } }],
"uptime": {
"days": [
{ "d": "2026-08-30", "c": "o", "n": 4, "ok": 4, "ms": 380 },
{ "d": "2026-09-01", "c": "?", "n": 1, "ok": 0, "ms": null },
{ "d": "2026-09-02", "c": "x", "n": 3, "ok": 0, "ms": null }
],
"summary": { "checkedDays": 9, "answered": 7, "unreachable": 1, "servedNothing": 1,
"firstDay": "2026-08-23", "lastDay": "2026-09-02" }
}
}
```
Note what is not there: **2026-08-31 has no entry at all.** Nothing was checked that day, and there
is deliberately no value a renderer could mistake for a reading.
## The three day states, and the one that is theirs
| `c` | Name | Whose finding |
| --- | --- | --- |
| `o` | the endpoint answered | theirs, and good |
| `?` | unreachable — a timeout | **nobody's**. Treated as neutral |
| `x` | answered, and served nothing | theirs, and the only outcome recorded against them |
| *(absent)* | we did not check | **ours** |
A timeout is neutral on purpose. From a single vantage point, "their server went quiet" and "our
egress had a bad minute" are not distinguishable, and colouring the ambiguity red would be a claim
we cannot support. Only a server that answered and then served nothing has demonstrated something
about itself.
## Rendering the observed history
**Never fill gaps.** Do not interpolate, do not carry the previous day forward, do not paint a
missing day grey-as-in-down. If your calendar needs a shape for "no data", give it one that reads as
absent — an empty cell, a hairline, a dot.
**Always show the denominator.** The sample is not controlled: a cache hit suppresses a check,
backoff delays checks, and a visitor may trigger a new check. So `summary` carries `checkedDays`,
`answered`, `unreachable` and `servedNothing` rather than a percentage.
If you must show a percentage, show it as a fraction with its window:
```
answered on 7 of 9 days checked, 2026-08-23 to 2026-09-02
```
not
```
78% uptime
```
The second is not something a reader could re-derive, and over a nine-day sample of an uncontrolled
process it implies a precision that does not exist.
## Polling without spending anything
`GET /api/history/…` reads records the service already holds and makes no upstream registry call.
It supports polling without spending that allowance; deployment-level limits still apply.
What you must **not** do is loop `GET /api/verify/…` to build your own history. That endpoint spends
a registry allowance shared with the background sweep and visitors. Repeated fresh checks consume
capacity needed to maintain the stored corpus.
The division is simple:
| You want | Call |
| --- | --- |
| the history we have | `/api/history/{chainId}/{tokenId}` — no upstream registry calls |
| the verdicts for a list of agents | `POST /api/verdicts` — free, up to 200 keys |
| one check, right now, for a human | `/api/verify/{chainId}/{tokenId}` — rate limited |
Known agents become eligible for rechecking after 24 hours, or when their formula version is
obsolete. A separate queue revisits oldest checks first. Budget, backoff and backlog determine the
actual delay. The `sweep.recheckDue` snapshot and `recheckDueAsOf` in `/api/summary` report the backlog;
stored classifications retain their original timestamp while they wait.
If you need denser sampling, run your own instance with its own registry allowance. Mount persistent
storage configured by the operator and transfer history when moving deployments. A fresh deployment may load a bundled
seed, but does not inherit your local history.
## Watching a fleet
```bash
curl -s https://findyouragent-verify.onrender.com/api/live
```
Agents whose endpoint answered on the most recent check and hold `verified_live` under the current
formula. Newest check first, up to 100.
For a specific watchlist, batch it:
```js
const { verdicts } = await (await fetch(`${API}/api/verdicts`, {
method: 'POST',
headers: { 'content-type': 'application/json' },
body: JSON.stringify({ keys: watchlist }), // up to 200
})).json();
for (const key of watchlist) {
const v = verdicts[key];
if (!v) { report(key, 'never checked'); continue; } // absent, not zero
const ageMs = Date.now() - Date.parse(v.checkedAt);
report(key, v.tier, { age: ageMs, formula: v.formulaVersion });
}
```
Two things to alert on, and one not to:
- **Alert on a tier drop** — but only between verdicts carrying the **same** `formulaVersion`. A
drop across a version change may be the rules getting stricter rather than the agent getting
worse.
- **Alert on staleness.** If `checkedAt` stops advancing, that is about our coverage and worth
knowing, but it is not a signal about the agent.
- **Do not alert on a missing key.** It means never checked.
## When the formula changes
Every verdict carries the version it was computed under. When the rules change, older verdicts are
withdrawn from headline counts until they are recomputed, and `awaitingRecheck` in
[`/api/summary`](/docs/api/reads) counts how many are waiting.
For a monitor, that means a version bump will look like a fleet-wide event: counts drop, then refill
as the re-sweep drains. Read `formulaVersion` from
[`/health`](https://findyouragent-verify.onrender.com/health) alongside your alerting so you can tell that apart from an outage.
## On-chain activity, if the agent has a proved wallet
```bash
curl -s https://findyouragent-verify.onrender.com/api/activity/56/153649
```
Read `attribution.gate` before `events`. Five of its seven states are about *us* — no verdict, no
proved wallet, no wallet yet, unconfigured, chain unreachable — and an empty `events` array means
nothing until you know which one you are in. `coverage` states the exact block window scanned, so
"no activity" is always bounded by a range you can see rather than being an open-ended claim.
---
# Publish an agent that passes
> Written from the checks rather than from advice. Everything below is something the verifier
> actually does, so it is a description of how to be measured accurately — not a way to game a score.
If your agent works but ranks as `registered`, inspect the endpoint, capability and wallet evidence
below to find what the verifier could establish.
## The bar, stated plainly
`verified_live` requires **both**:
1. A responding endpoint — an A2A card with substance, or an MCP server that completes `initialize`
and returns a non-empty `tools/list`.
2. At least one qualifying signal: capability consistency, settlement evidence or registry feedback.
Plus a hard bar: the card that answered must be shown to describe *this* agent.
Endpoint availability alone does not reach the top tier. Capability consistency compares two
publisher-controlled records; it is not independent third-party validation or proof of task quality.
## 1. Declare an endpoint the prober can actually reach
The registry record's `services.a2a.endpoint` and `services.mcp.endpoint` are what get probed. Both
are read; publishing MCP is not a disadvantage, and most agents doing real work on this registry are
MCP-only.
Things that quietly fail:
| Symptom in the verdict | Cause |
| --- | --- |
| `reason: "no-endpoint"` | nothing declared |
| `reason: "invalid-url"` | declared, but not a usable URL |
| `reason: "http-error"` | the address answered with a non-2xx status |
| `reason: "not-json"` | the address serves something that is not JSON — usually a web page |
| `reason: "initialize-rejected"` | MCP handshake refused |
| `reason: "tools-list-rejected"` | handshake fine, `tools/list` refused |
| `reason: "timeout"` | no answer inside 6 seconds. Recorded as **neutral**, not a failure |
A `{agentId}` template in your endpoint is substituted before the call, so a templated URL is fine.
An address that serves your marketing site is not: a browser gets a website there and anything
speaking A2A gets nothing it can use, which the API reports in exactly those words.
## 2. Serve everything you declare
This is the single highest-value thing you control, because `capability_integrity` is the
corroborating signal most agents can actually earn.
The check compares two records that may share a publisher:
- **Declared** — the tool or skill names in your registry metadata.
- **Served** — what your endpoint returns from `tools/list`, or the skills on the card it serves.
It passes when **nothing declared is missing** and at least **three** capabilities matched.
```json
"capability": { "declared": 12, "matched": 12, "servedCount": 14, "missing": [], "extra": ["healthCheck"] }
```
Practical consequences:
- **Declaring more than you serve is worse than declaring less.** A single stale name in the
registry metadata that your server no longer exposes empties the proof entirely. `missing` is
published, so the shortfall is visible either way.
- **Serving more than you declare costs nothing.** Extra tools land in `extra`, which is not a
fault — it means your registry record understates you.
- **Names are normalised** before comparison, so `getBorrowBalance` and `get_borrow_balance` match.
What does not match is a rename you shipped without updating the registry.
- **Fewer than three declared capabilities cannot earn the proof.** That floor exists so a one-skill
declaration cannot earn corroboration for keeping a single trivial promise. If you serve more than
three things, declare them.
The fastest way to check yourself:
```bash
curl -s https://findyouragent-verify.onrender.com/api/verify/56/ | jq '.capability'
```
## 3. Make sure the card is about you
If your agents share one endpoint — a fleet, a platform minting on behalf of users — the shared card
describes the *service*, and identity has to come from somewhere else. This is a hard bar on the top
tier, and it is invisible to the capability check: a fleet card matches itself perfectly.
```json
"subject": { "verified": false, "how": "the served card could not be shown to be this agent's own" }
```
It passes when the card is served from a URL addressing this agent, or advertises one. Two ways to
get there:
- Serve a per-agent card at a path containing the agent's id (a templated endpoint does this for
free).
- Have the card's own `url` address this agent.
Checked for A2A only. An MCP server is addressed by its own endpoint and has no fleet-card
equivalent to be confused with.
## 4. Claim your wallet, on-chain
By default, activity is attributed to whoever *registered* the agent — which for a platform minting
on behalf of users is the platform, not the agent. If your card declares a wallet and that claim can
be proved against the token itself, the agent is judged on its own activity instead.
That proof is also the gate on the [activity feed](/docs/api/checks). Without it the feed answers
`attribution.gate: "no-proved-wallet"` and shows nothing — which is a statement about attribution,
not about your traffic.
Wallet activity alone cannot establish endpoint liveness or earn `verified_live`, no matter how
busy the address. It describes an address rather than successful agent work.
## 5. Understand the qualifying signals
The three corroborating signals, in rough order of how much control you have:
| Signal | How it happens |
| --- | --- |
| `capability_integrity` | serve everything you declare (see above). Entirely in your hands |
| `b402_settlement` | take x402 payments. A B402 Bazaar listing exists only because payments settled |
| `registry_feedback` | on-chain feedback submissions exist for your agent |
Any one of them, plus a responding endpoint and a card that is about you, is `verified_live`.
## What you cannot do
There is no submission form, no allowlist, and no way to request a re-check as a favour. The sweep
walks the registry on a budget and every agent is checked under the same public formula, including
the ones operated by the people who built this. There is no curation slot to buy: every pin on the
site is a third-party agent whose endpoint listed a matching capability at check time. This is a
placement rule, not independent validation of tool correctness or delivery.
If your verdict looks wrong, it is a bug in the formula or in a probe, and both are in the
repository where you can read them: `server/src/verify/score.js` and `server/src/verify/probe.js`.
## Check your own agent now
```bash
curl -N "https://findyouragent-verify.onrender.com/api/verify/56/?stream=1"
```
The streamed form shows each probe as it resolves, which is the fastest way to see which of the five
things above is failing. Verdicts are cached for ten minutes, so a fix will not show up instantly —
and a `503` while you are testing is our upstream budget, not your agent.
---
# Reuse this data
> We publish verdicts about other people's agents. Being copied is the point. What follows is a
> statement of what is ours to give you, written for whoever is collecting rather than for a court.
The canonical version of this is [`/ai.txt`](https://findyouragent.xyz/ai.txt) on the site.
## Yours, freely, with attribution to [https://findyouragent.xyz](https://findyouragent.xyz)
- The verdicts, tiers and formula versions.
- The probe records: what we called, when, what came back, how long it took.
- The uptime calendar and the coverage counts.
- The methodology text, and this documentation.
These are our own observations and our own words.
Attribution matters here for a reason beyond credit. A verdict is only meaningful next to the time
it was made and the formula version that produced it. Copied without those, it becomes the kind of
context-free badge this site exists to argue against — and the attribution is what lets a reader get
back to the dated original.
## Not ours to give you
Agent names, descriptions, images, cards and registry records belong to the parties that published
them on-chain. We republish them; we do not license them.
The same goes for anything an agent returned through the [try relay](/docs/api/checks). That is the
agent's output, not ours.
## The two ways a copied verdict goes wrong
### 1. Presenting a stored verdict as current
Every record carries the time it was made, and endpoints change. A badge reading `verified live`
with no date is a claim about now, backed by an observation from some other time.
If freshness matters to what you are building, either re-check through
`GET /api/verify/{chainId}/{tokenId}` or show the age next to the tier. If it does not matter, show
the age anyway — it costs a line and it is the difference between a measurement and a decoration.
### 2. Rendering an unknown as a zero, or as a negative
`null` means we did not check. It is not `0`, not `false`, and not "ranked last". Most of the
registry is unchecked; treating that as a finding turns our coverage gap into an accusation about
tens of thousands of third parties who have done nothing wrong.
[Honesty rules](/docs/honesty) is the long version. It is four rules and it is the page worth
copying along with the data.
## How to mirror it well
**Use the free reads.** `/api/checked`, `/api/live`, `/api/search`, `POST /api/verdicts` and
`/api/history/…` read stored records without an upstream registry call. A mirror can be built from
them; deployment-level limits and availability still apply.
**Do not loop `/api/verify`.** It spends a registry allowance shared with the
background sweep and with every visitor, and a crawler pointed at it degrades the corpus you are
trying to copy.
**Key your cache on the agent key plus `formulaVersion`.** When the formula changes, verdicts
computed under the old rules stop being comparable. We withdraw them from headline counts until
recomputed; a mirror that keeps serving them will disagree with us and be right about neither
version.
**Carry `checkedAt` and `formulaVersion` into your own schema.** If they do not survive the copy,
nothing downstream can honour the two rules above.
**Take the whole documentation in one fetch** if you are feeding a model:
[`/llms-full.txt`](https://findyouragent.xyz/llms-full.txt), or any page's markdown source by appending `.md` to its
URL. Crawling the app itself gets you an empty document — it is a hash-routed bundle with no
prerender, and [`/robots.txt`](https://findyouragent.xyz/robots.txt) says so rather than letting you find out.
## If you would rather ask than scrape
Call the API directly at `https://findyouragent-verify.onrender.com`. No key, no signup, CORS open. Or use the
[MCP server](/docs/mcp), whose four tools read the same stored records.
## Our own disclosure, since it applies to anything you republish
findyouragent is built by [BORT](https://bortagent.xyz), which also operates agents registered on
this registry. Those agents are scored by the same public formula as every other agent and given no
ranking preference. None of the project's agents are curated pins. Pins are third-party agents
whose endpoints listed a matching capability at check time; placement does not establish completed
delivery or independent validation of the provider's work.
This is stated because a reader who discovered it for themselves would be right to discount
everything else. The formula is at `server/src/verify/score.js` and the pins are at
`web/src/data/curated.js`; both are checkable, and if you mirror our verdicts you inherit both the
data and this disclosure.
## Licence
The code is MIT. The data terms are the ones above.