# Report how it went

> After you use a business's door (its inbox, MCP server, A2A agent or API), tell this directory how it went: done, refused, your own mistake, failed, or needs a person. One call, no sign-in, no pass, no key needed.

Your reports make us re-check doors, so your searches send you to doors that work. A report counts the same whatever it says: a door that worked is as useful to know as one that failed.

## What a report is, and what it is not

- A report measures the door: did it answer, did it do the operation, refuse it, fail, or need a person, and how long it took. It is not a review, and it does not say whether the business kept its promise afterwards.
- It goes privately to the business, as counts by day. On its own it changes nothing anyone else sees.
- When you report that a door could not be reached, this directory may read that door itself: at most twice a day per door for reports like yours, and only for the doors it reads itself (an agent inbox, MCP, A2A, UCP, ACP, an API description), not a booking platform's page or a declared API. A door is marked failing by this directory's own reads, never by reports.
- A report carries no person and nothing that was said: no pass, key, name, email, phone, address, message, item id, free-text reason or trace. A call that sends any of them is refused whole.
- Tell the person you act for, once, that you report how businesses' doors answered: only whether the door worked, never anything about them.

## The call

`POST https://network.surfingdog.ai/v1/door-reports` with a JSON body, or the MCP tool `report_door` at https://network.surfingdog.ai/mcp with the same object as its arguments.

```json
{
  "v": 1,
  "reports": [
    {
      "domain": "bakery.example",
      "door": { "type": "inbox", "url": "https://bakery.example/mcp" },
      "op": "book",
      "tool": "create_booking",
      "at": 1791892777,
      "ms": 1840,
      "intent": "5mQ2c1Kc8Qx",
      "result": "fail",
      "class": "tcp.timed_out"
    }
  ]
}
```

The answer is `202`, every report either accepted or ignored, by its place in `reports`:

```json
{ "accepted": [{ "i": 0, "proof": "none", "counts": "counter" }], "ignored": [], "next": "…" }
```

`proof` is what proved a report: `signature` when your call's signature verified, else `none` (`token` once this directory checks door tokens). `counts` is what it was kept as: `counter`, a count by day, or `row`; both are private.

An ignored report says why, checked in this order: `unknown_door` (not a door this directory shows for that domain, or a URL with a query or a fragment), `unknown_op`, `bad_class`, `bad_time` (more than 7 days old, or more than a minute ahead), `superseded` (a later report in the same call is the same attempt) or `over_limit` (your share for the day is used up).

## The fields

| Field | What to send |
|---|---|
| `domain` | The business's domain, as the directory lists it. |
| `door` | `type` and `url` exactly as a search, `get_business` or a listing gave them. For a business's inbox: type `inbox`, with the address you used (the card's `inbox.url`, `inbox.mcp` or `inbox.rest`). For any other door: its `type` and `url` from the listing's `doors` (`mcp`, `a2a`, `openapi`, `platform:<name>`…). |
| `op` | What you tried, from the capability vocabulary: `find`, `availability`, `message`, `book`, `order`, `pay`, `change`, `cancel`… (https://surfingdog.ai/v1/score-rules). |
| `tool` | Optional. The tool or method you called, in lowercase, up to 64 characters of `a-z 0-9 _ . -`. |
| `at` | When you used the door, in Unix seconds (kept to the minute). Within the last 7 days. |
| `ms` | Optional. How long the door took to answer, in milliseconds, up to 600000. The business sees it; nobody else does. |
| `intent` | 8 to 32 characters of `A-Z a-z 0-9 _ -`, made fresh for each attempt and sent again with its retries. An attempt counts once, and its last result wins. |
| `result` | `ok`, `refused`, `invalid`, `fail` or `info`. |
| `class` | For every result but `ok`, what happened (below); none with `ok`. |
| `token` | Optional. When a door's answer carries a signed outcome token, send it here as it came, and keep it: it is your proof of what the business answered. |

The body is strict: a member not in this table (in any letter case), a member named twice, or a value of the wrong type or outside its pattern is refused whole with `400 malformed`. More than 100 reports, more than 128 KB, or a token over 1 KB is `413 too_large`.

## Results and classes

| Result | Classes | When |
|---|---|---|
| `ok` | none | The door did what you asked. |
| `refused` | `slot_taken`, `out_of_stock`, `item_unavailable`, `outside_limits`, `wrong_state`, `customer_side` | An honest no. That is the door working, never a failure. A declined payment, an address the business does not deliver to and an eligibility refusal are all `customer_side`: never say why about your person. |
| `invalid` | `client.invalid_params`, `client.parse_error`, `client.invalid_request`, `client.mcp_headers`, `client.mcp_refused`, `client.http`, `client.rate_limited` | Your own request was at fault (JSON-RPC -32602, -32700, -32600; MCP -32020, -32021; an HTTP 4xx other than 408 and 429; every 429). The business sees these per tool, privately; they never count against it. |
| `fail` | `dns.name_not_resolved`, `dns.failed`, `tcp.timed_out`, `tcp.refused`, `tcp.reset`, `tls.cert.invalid`, `tls.failed`, `http.error`, `http.response.invalid`, `abandoned`, `timeout`, `operation.timeout` | You could not reach the door, or it did not answer. These make the directory read the door itself. |
| `fail` | `protocol.internal`, `protocol.advertised_missing`, `protocol.version`, `protocol.invalid_answer` | The door answered with a protocol error (JSON-RPC -32603, -32601; MCP -32022; A2A -32004, -32009), or an answer that does not follow its protocol. |
| `fail` | `operation.tool_error`, `operation.failed`, `operation.internal`, `payment_failed` | The door took the call and the operation failed on its side. |
| `info` | `escalation`, `auth`, `person` | The door needs a person to go on. |

## Signing, if you can

Unsigned reports are welcome. A signed call tells the business more about where reports come from, never who:

- `sdi-agent/1`: an RFC 9421 signature with a key you hold yourself, sent in `Sdi-Agent-Key`, covering `@method`, `@authority`, `@path`, `content-digest` and `sdi-agent-key`. No pass is needed.
- Web Bot Auth: a platform's signature tagged `web-bot-auth`, with `Signature-Agent` naming its origin and its key directory at `/.well-known/http-message-signatures-directory`. The signature must also cover `@method`, `@authority`, `@path` and `content-digest`.

Your signature must name the host you send it to (`@authority`): sign for `network.surfingdog.ai` when you call https://network.surfingdog.ai, and for `surfingdog.ai` when you call https://surfingdog.ai. A signature that does not verify makes the call unsigned, and the answer's `Sdi-Signature` header says why. A business never sees a key; it sees a platform's origin when 5 or more of the platform's sources reported, and none below that. A signed reporter also earns a larger reading allowance (below).

## A larger reading allowance

Sign your reports, and the reads that found the businesses, and you can read this directory on an allowance of your own.

- **Points.** A signed report earns you 1 point for its business, once a day, when your own signed reads returned that business here today or yesterday (UTC): a search or a lookup that listed it. What the report says never matters: a door that worked earns what a door that failed does. A day is this directory's UTC day, the day your reports arrive, and counts at most 10 points. A platform earns none at businesses on its own registrable domain. Unsigned reports earn nothing.
- **Contributor.** 30 points in the last 30 days, on at least 7 different days.
- **What it gives.** A contributor's signed reads of `/mcp`, `/a2a`, `/v1/businesses` and `/v1/businesses/{domain}` count against its own allowance: 1,800 a minute in bursts of 600 for a key, 6,000 a minute in bursts of 2,000 for a platform (all its origins together), and at most that much from one address. When it runs out, the limits everyone has still apply.
- **What it never gives.** Different answers, a different order, sooner reads of a door, or any weight in a ranking, a score or a track record. A business is never told who contributes.
- **Signing a read.** sdi-agent/1, as above, or Web Bot Auth covering at least `@authority` and `signature-agent`, from a platform whose reports this directory has had. Sign with the key you report with, for the host you send to. A signature counts once: sent again, the read is anyone's. A read is never refused for its signature, and its answer never says whether the signature counted: ask for your own credit (below). Over MCP or A2A, a report signed over the whole request (method, authority, path and the body's digest) is yours, as it is on `https://network.surfingdog.ai/v1/door-reports`, and `Sdi-Signature` says why when it is not.
- **Your own credit.** `GET https://network.surfingdog.ai/v1/door-reports/me`, signed the same way, answers your points, whether you are a contributor and what you read with. The signature is checked before anything is looked up, so nobody can ask about anyone else.
- **What is kept for it.** Your key or platform as a keyed hash that changes every 30 days, the day, and how many businesses you reported at; which businesses, only as bits of a keyed hash, cleared within a minute of the day's end. Rows go after 31 days, and at most 100,000 reporters, those with the most points, are kept. Of a signed read, nothing is kept with your key: not the query, not the answer. Only, in memory, that its signature was used, until it expires, and for two days a keyed hash of your key with each business it was answered with, which names neither.

## Limits

- 60 calls a minute from one address; up to 100 reports and 128 KB a call; a token is at most 1 KB. Over MCP, a request body is at most 16 KB.
- Reading: 600 requests a minute from one address, in bursts of 200, on `/mcp` and `/a2a` (with the limits per person and per assistant platform that https://network.surfingdog.ai/llms.txt lists), and the same on `/v1/businesses` and `/v1/businesses/{domain}`; a contributor reads on its own allowance before these (above).
- A self-held key: 1,000 reports a day, 50 at one door. A platform: 100,000 a day, 5,000 at one door.
- Report soon after each use, or in batches. Reports older than 7 days are ignored.

## Where the hint comes from

Every answer about businesses from the directory search (a list, a listing, a result at https://surfingdog.ai/b/<domain>.json) and from the A2A door carries `report: {tool, url, guide, reward}` pointing here; the MCP tools' answers leave it out.
