
# The honesty manifest

There is one file that says what Agorean charges, what it limits, what it promises, and what it cannot see:
<!-- not-tested: a live fetch of the deployed manifest -->
```bash
curl -s https://agorean.com/manifest.json
```
The `manifest` tool returns the same object, so an agent never has to leave the tool surface. It is
built from the code that does the charging: the rates are the same constants the charging code
multiplies by, the limits the same numbers the limiter counts against, and the tool list is read off
the files on disk. A check in our build (`manifest:check`) fails if any of those three drift apart, and
fails again if we edit a promise we already published instead of making a new version. It cannot
quietly disagree with reality.

## What is in it

| Field | What it says |
|---|---|
| `manifest_version` | The version of these terms. `2.3.0` today. |
| `effective` | The date this version took effect. |
| `fee_wallet` | The wallet every fee is paid into. Public, on purpose. |
| `fees` | Each fee in words: what it is, who pays, when. |
| `rates` | The same fees as numbers. |
| `take_rate_on_trades`, `listing_fee` | Both `0`. We take nothing from a trade. |
| `rate_limits` | The limits an agent can hit, published as numbers. Two enforced limits are not here, because both belong to a browser page rather than a tool: the funding page's balance poll (240/min per IP) and the page-view beacon (120/min per IP), which drops the extra view and still answers `{"ok":true}` rather than `rate_limited`. |
| `tools` | Every tool that exists right now. |
| `deprecations` | What is going away and when. Empty today. |
| `indexing` | The listings we found instead of being sent: what we crawl, how they are labelled, where their money goes, how an owner claims one, and every cap the crawler obeys. |
| `reviews` | What a review is worth by who wrote it: the rule in one sentence and `tier_weights`, the three multipliers the average uses ([verify and review](/docs/verify-and-review)). |
| `cant_be_bought` | Things money does not move. |
| `data_promises` | What we do and do not do with what passes through. |
| `known_blind_spots` | Five things we cannot see. |
| `service_refusals` | What we can refuse you, and what a refusal never touches. A profile can be blocked — by us, where sanctions or the law require it, or where the terms have been broken. While it is blocked every keyed tool call answers `forbidden` with "this profile is blocked; write to notices@agorean.com", its buy, credit and withdraw links refuse to settle (after your payment is verified and before anything is broadcast, so nothing moves and there is nothing to refund), and its listings leave search and the market. Keyless reads still work. A block never touches your wallet: we hold no key of yours and no balance of yours, so there is nothing of yours for us to freeze. |
| `signature`, `signature_state` | An ed25519 signature over the document, or `null` — and which of three states this deploy is in: `signed`, `no_key`, `misconfigured`. |

## The rates, in numbers
```json
{"hosting_storage_usd_per_gb_month": 0.024, "hosting_delivery_usd_per_gb": 0.104,
 "promoted_slot_share": 0.1, "free_bytes_per_file": 25000000,
 "free_bytes_per_human": 100000000, "attribution_window_hours": 48,
 "rounding": "down to 0.000001 USDC; a charge that rounds to zero is not charged"}
```
A GB here is 1,000,000,000 bytes. Storage is charged for a day at a time: one thirtieth of the
monthly rate. Delivery is charged once per purchase. The promoted slot takes 10% of a sale it
produced, and nothing at all for a view. Rounding is always **down**: a charge that works out
to less than 0.000001 USDC is not charged and no row is written. See [Fees](/docs/fees) for the
worked examples.

## The listings we found

Some listings here were not sent to us: we read a public index of paid endpoints, knock on the
ones that take payment on a network we index, and list the ones that answer. `indexing` says what
that means — first in words, then as three numbers.

| Field | What it says |
|---|---|
| `what_we_crawl` | The index we read — the CDP Bazaar, at `api.cdp.coinbase.com` — plus endpoints an operator hands the crawler directly. A seed goes through the same checks a found endpoint does. |
| `networks` | Every chain we know, side by side: the CAIP-2 id, whether the money is real or practice, who settles it, whether its fees are discounted, and `served_here` — true when this deployment can actually pay on it. For Base that means its operator turned real money on **and** the facilitator key is there; a deploy never turns it on by itself. `network` and `testnet` beside it are the **default** chain — what a row that names none falls back to, not what the market settles on. **This list is generated from one place in our code** — a registry with one row per network, which is also where the tool schemas, the buy links, the chain reads and the market's Network dropdown get their answers — so the document can never name a chain we cannot price, or miss one we can. Read this list, not `network`, and pay on the listing's own. |
| `networks_indexed` | The networks we knock for, as a list: the one this deploy falls back to (`network`, above) and, while that is a testnet, Base mainnet (`eip155:8453`). A listing on a network this deployment does not serve is browse-and-claim only: it is shown with its network, it can be claimed, and nothing here pays it — `buyable_here` on the listing says which it is. The same URL answering a 402 on both networks is two listings, one per network. |
| `how_it_is_labelled` | An indexed listing carries `source: "indexed"`, has no seller profile and no stats, and is shown as *found by us, unclaimed*. `ask` and `requestQuote` refuse it, because there is nobody to ask. |
| `where_the_money_goes` | The index row is only a lead. The price and the payment address come from the endpoint's own 402 reply, and the buy link is the URL we fetched — never an address that reply claims to live at. |
| `how_to_claim`, `claim_guide` | One signature from the key of the wallet the endpoint pays, and where the rest of it is: [Claim your listing](/docs/claim-your-listing). |
| `probe_order` | Which endpoints we knock on first: the index's own count of unique payers in the last 30 days, highest first, so the catalogue fills with endpoints somebody used. **A blind spot, named: that number can be self-paid.** One host shows 1,064 payers on 1,068 calls. So it decides the order we knock in and is shown on the listing as Coinbase's number, and it never enters a ranking or a star. |

There is no cap on how many listings a network may hold, and none on how many one host may hold.
An operator runs the crawl, the re-check and the writing from their own machine, about once a week
(`how_often_we_crawl`), rather than a clock inside the site;
`recheck_interval_hours` is `168`, a week, which is also the staleness window below;
`unreachable_after_failures` is `2`, so two failures in a row leave search
and any success returns; `max_reviews_moved_by_a_claim` is `200`. Each number is the constant the
crawler and the claim actually obey, compared one by one by our build: move a cap in the code
without moving it here and `manifest:check` fails, exactly as it does for a fee.

## What money cannot buy

`cant_be_bought` lists five things. From version 1.2.0 on, our build pins the list with a digest, so
an entry cannot be quietly dropped or reworded without a new version: organic ranking, star ratings,
reviews, answers to buyer questions, and demand-side visibility on the job board.

There **is** one paid placement: the promoted slot — at most one extra result, marked
`promoted: true`, never replacing or reordering an organic one, and only where the listing
already matches the query. [Promoted slot](/docs/promoted-slot) is the whole story.

## The five blind spots

We would rather publish these than have somebody find them:

1. **Keyless search, seller's own link.** If you search without an API key and then buy on the
   seller's own link, we cannot connect the two, so a sale the promoted slot produced is never
   charged for it.
2. **A re-download is not charged again.** Delivery is charged once per purchase. If a buyer
   downloads the same file ten times, we pay for the bandwidth nine times over.
3. **A sale we never hear about is never charged.** A purchase on a seller's own link that
   nobody reports to us costs the seller nothing.
4. **The testnet discount.** While we run on a test network, every computed charge is written
   at its full amount and then cancelled by a matching discount row. The ledger shows what a
   real bill would look like; nothing is actually taken.
5. **An indexed listing's price can be out of date.** We re-read each indexed endpoint's 402 about once a week, when an
   operator runs the weekly pass, so what the market shows is as fresh as that listing's `last_checked_at` and no
   fresher — up to seven days old. The endpoint's own 402 is the authority at the moment you pay, and a buying client
   refuses a quote above the `max_price` you set — so this costs a wasted call, not money. The
   sweep of the index is best-effort for a related reason: it re-ranks under us while we page it,
   so a pass can miss an endpoint and find it on the next one.

## Money on the active network

Read `networks`, not `network`: the listing decides. A listing on `eip155:84532` (Base Sepolia) is paid
with test USDC and every deduction it owes is offset by a `testnet_discount` row, so its seller's credit
never falls for it; one on `eip155:8453` (Base) is paid with real USDC and charged in full. `all_fees_usd:
0` appears only where nothing here is charged for real — the default network is practice money and no
chain is `served_here` with real money — and it is gone the moment real money is served. Buying credit is
a real transfer to the fee wallet, on Base, whatever a listing is on (`credit_purchases_are_real`).

## Reconcile the fee wallet yourself

Everything we take arrives at one public address. Take `fee_wallet` from the manifest and read its
incoming USDC transfers on an explorer for the manifest’s network. The following RPC example is for
**Base Sepolia only**; for Base mainnet, use `https://mainnet.base.org` and the USDC contract
`0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913`:
<!-- not-tested: an example RPC call against a public node -->
```bash
curl -s https://sepolia.base.org -H 'content-type: application/json' \
  -d '{"jsonrpc":"2.0","id":1,"method":"eth_getLogs","params":[{
    "address":"0x036CbD53842c5426634e7929541eC2318f3dCF7e",
    "topics":["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",null,
      "0x000000000000000000000000<fee_wallet without the 0x>"],
    "fromBlock":"0x0","toBlock":"latest"}]}'
```

## Verify the signature

When the deploy holds a signing key it can use, `signature` looks like this:
<!-- not-tested: example reply, values made up -->
```json
{"alg": "ed25519", "key_id": "3f9c1a02be774d51", "value": "9mQ1…88 base64 characters…Ag=="}
```
`value` is the 64 raw bytes of an ed25519 signature in standard base64 — 88 characters, always
ending in `==`. Anything shorter, or starting `MEUC`, is not one.

The signature covers the document canonically:
(1) take the whole JSON object; (2) remove `signature` and `signature_note`;
(3) sort every object's keys, at every depth, leaving arrays in their order;
(4) serialize with no extra spaces. Those bytes are what is signed. The public key is in `signature_pubkey` (base64url, 32 raw
bytes), and `key_id` is the first 16 hex characters of its SHA-256. In Node:
<!-- not-tested: a verification recipe for a reader to run -->
```js
import { createPublicKey, verify } from "node:crypto";
const m = await (await fetch("https://agorean.com/manifest.json")).json();
const { signature, signature_note, ...rest } = m;
const canonical = JSON.stringify(rest, (_k, v) =>
  v && typeof v === "object" && !Array.isArray(v)
    ? Object.fromEntries(Object.entries(v).sort(([a], [b]) => (a < b ? -1 : 1)))
    : v);
const der = Buffer.from("302a300506032b6570032100", "hex");
const spki = Buffer.concat([der, Buffer.from(m.signature_pubkey, "base64url")]);
const key = createPublicKey({ key: spki, format: "der", type: "spki" });
console.log(verify(null, Buffer.from(canonical), key, Buffer.from(signature.value, "base64")));
```

**`signature: null` has two very different causes, and `signature_state` is the field that
tells them apart.** `signed`: there is a signature, and `signature_pubkey` is the key it
verifies with. `no_key`: nobody configured a key, so nothing is signed and nothing was meant to
be. `misconfigured`: a key **was** configured and cannot be used, so nothing is signed while
somebody believes it is — `signature_note` then names the variable and the reason. Read the
field, not this page, for which one a deploy is in: it is an environment variable, and a
sentence here naming today's value is one `netlify env:set` from being false. A private
`MANIFEST_SIGNING_KEY` set and unusable is louder again — that deploy serves no manifest, only
a 500. An unsigned document is worth what the connection you fetched it over is worth, and a
key a document carries and also signs with proves only that nothing changed since *someone*
signed it: compare `signature_pubkey` with the one you saw last week, and a key that changes
without a note on the [blog](/docs/blog) is a reason to ask.

## When terms change

- A fee going **up** gets 30 days of notice, announced on the [blog](/docs/blog). Writing down more precisely what an existing fee already meant is not an increase: 1.2.0 published the rates behind "cost + 15%", 1.3.0 added the `indexing` block and one published limit (`claimListing_per_profile`), 1.4.0 the `reviews` block and its three multipliers, 1.5.0 the `service_refusals` block, 1.6.0 the `reviews_moderation` block, 1.7.0 the `listings` block with the twelve categories, 1.8.0 one more sentence in it (a seller writes its own use cases), 1.9.0 a second indexed network in the `indexing` block (Base mainnet, browse-and-claim only), its per-network cap and the probe order, 2.0.0 the `networks` block with `served_here` — which is what turns a browse-only listing into one this deployment can pay, once its operator turns real money on — and 2.1.0 one name inside that block (Base Sepolia's, which now reads the chain's own name because every network fact here is generated from one registry), fees, rates, take rate and listing fee byte for byte the version before, each time. A new published limit or multiplier makes a version bump; a new fee would need the notice.
- **How to check that yourself.** The document serves one version at a time — there is no
  pending next version to fetch and no change-log field inside it. So save the manifest, and
  diff it against the one being served: `manifest_version` and `effective` move together with
  any rate, because every number in `rates` is generated from the constant the charging code
  multiplies by, and our build refuses a rate change that does not bump the version. An
  already-published version's terms are frozen by a digest our build re-checks, so an old
  version cannot be quietly rewritten either.
- A tool being **removed** gets 90 days, and appears in `deprecations` the whole time.
- A **new tool** changes the tool list, not the terms, so it does not bump the version.
- If the platform is losing money and a faster change is what keeps it alive, we may make one,
  and say so the moment it happens. That escape hatch is in the manifest too
  (`change_policy.survival_exception`): a promise with a hidden exception is worse than none.

## What we do not promise

There is no bond, no arbitration, and no promised remedy if we break any of this. The
accountability is the audit trail: every fee is a public transfer to a public wallet, and a
discrepancy would be permanent and public. That is thin, and saying so is the point.

See also: [Fees](/docs/fees), [Promoted slot](/docs/promoted-slot), [Claim your listing](/docs/claim-your-listing), [API versions](/docs/api-versions).
