# Check before you pay

Version 2026.09.4.

You have a candidate x402 endpoint and you are about to pay it. Before you do, ask what has
already been observed about it. This is the whole pattern; everything below is the same two
calls with the parts filled in.

Both tools below answer whether paying delivered what the listing said, from a settled payment.
Neither checks protocol conformance or schema declarations, which a free handshake can already
tell you and does not need paying anyone to find out.

## 0. One GET, if you hold a 402 and nothing else

```bash
curl -sS 'https://api.teppi.xyz/v1/check?url=https%3A%2F%2Fseller.example%2Fv1%2Fextract'
```

Same answer as the tool in section 1, unwrapped, with no MCP client and no JSON-RPC envelope. The
query string of the url you hold may differ from the listing's example; the record matches on the
path then and says `"matched": "path"`. Add `&method=POST` if you know the verb.

Add `&pay_to=<the payTo in the 402>` and the answer says what the record knows about whoever
gets paid, which is often more than it knows about the url. Every answer is signed by the key
the key document lists with `"purpose": "check"`, so it can be shown to whoever you act for.

A url the record has never seen answers `UNRATED` with `"queued": true`: the question itself
puts the url in line for a free handshake, the same one `npx teppi-check` sends, within the
hour, and the next answer carries what it said. Nothing an asker sends is ever recorded as an
observation; only what the endpoint answered is.

## 1. Ask what has been verified

```bash
curl -sS https://api.teppi.xyz/mcp \
  -H 'content-type: application/json' \
  -d '{
    "jsonrpc": "2.0", "id": 1, "method": "tools/call",
    "params": { "name": "check_grade", "arguments": { "id_or_url": "https://seller.example/v1/extract" } }
  }'
```

MCP wraps the answer; the fields that matter are in `result.structuredContent`, and
`result.content[0].text` carries the same thing as a JSON string for a client that only reads
text. This is the reply to the exact call above, for a url Teppi has never seen, with the signature
shortened:

```json
{
  "jsonrpc": "2.0", "id": 1,
  "result": {
    "structuredContent": {
      "band": "UNRATED", "tier": null, "composite": null,
      "why": "this endpoint is not in the record yet, so nothing has been observed about it",
      "defects": [], "asked": "https://seller.example/v1/extract", "matched": "none",
      "queued": true,
      "next": "ask again in an hour: a free handshake is queued and its answer will be here",
      "reproduce": "npx teppi-check https://seller.example/v1/extract",
      "answered_at": "2026-09-26T14:00:00.000Z", "signing_key_id": "c20260920",
      "signature": "ed25519:<base64>"
    },
    "content": [ { "type": "text", "text": "... the object above, as a string ..." } ],
    "isError": false
  }
}
```

An endpoint Teppi has probed but not enough yet also answers `"band": "UNRATED"`, but with a
`tier` and a real `observations` count still climbing toward the thirty paid samples and
fourteen days a letter needs. Every answer carries `reproduce`, the free handshake you can run
yourself against the seller, and is signed by the key the record publishes for checks. Once an
endpoint clears both, the same object carries a `band` of `A` through `F`, the `composite`
behind it, and `observationsSince` and `lastSeen` for how much of that history is recent.

## 2. Read it before you pay, not after

- **`defects` is not empty** — the listing itself is broken (a placeholder never filled in, a
  chain it does not actually offer, a price it does not actually charge). Stop here regardless
  of the band; a good band on a broken listing means the probe found a way around the break,
  not that a normal caller will.
- **`band` is `UNRATED`** — not observed enough to say, not the same as bad. Weigh it like
  any other unknown, and consider running `npx teppi-check` yourself before committing.
- **`band` is `D` or `F`** — probed and found wanting. `why` says on what basis.
- **Otherwise** — `composite`, `tier` and `observations` say how much weight the number can
  carry. A B built on 30 outcome-verified samples over three weeks is a different claim than a B
  built on four.

## 3. Or look for an alternative first

```bash
curl -sS https://api.teppi.xyz/mcp \
  -H 'content-type: application/json' \
  -d '{
    "jsonrpc": "2.0", "id": 1, "method": "tools/call",
    "params": { "name": "search_capabilities", "arguments": { "query": "extract fields from a pdf", "sort": "verified" } }
  }'
```

Sorted `verified` first, so whatever has the most evidence behind it is first in the list, not
whatever pays for placement. Nothing here can be paid for: the same rule that keeps a grade from
being bought keeps rank from being bought.

## Everything above without an SDK

Both are one JSON-RPC call to one endpoint, `https://api.teppi.xyz/mcp`, and the first is also
one GET at `https://api.teppi.xyz/v1/check`. Anything that can send a request and read JSON
back can do this, whatever the caller is otherwise built with.

For the same check inside the official x402 client, any fetch, Python or an MCP config, see
https://api.teppi.xyz/docs/integrations.

---

## Changelog

### 2026.09.4

| Change | Reason |
|---|---|
| The example reply carries its signature, every answer is said to carry `reproduce`, and the page points at the integrations page | The reply was called unedited while it lacked the signature every answer carries, and the page said a listed endpoint has no `reproduce` field when every answer has one |

### 2026.09.3

| Change | Reason |
|---|---|
| Added the one GET form, the path match, and what asking about an unseen url sets in motion | An x402 client at the moment of paying holds a url and a 402, not an MCP session, and the url it holds carries its own query rather than the listing's example. A question about a url nobody listed used to end in nothing; now it ends in a handshake |

### 2026.09.2

| Change | Reason |
|---|---|
| Said what these two tools do not check, before showing how to call them | A reader arriving from an MCP registry may already know a different kind of check, one that never pays anyone |

### 2026.09.1

| Change | Reason |
|---|---|
| First published | The method page said how a grade is computed. Nothing said what to actually send. |
