# How to check whether a web page has changed since you read it, step by step with curl

Last updated: 2026-10-13

To find out whether a page you read earlier still says the same thing, send its receipt (or its URL and text hash) to `POST /v1/recheck` (US$0.003 per call). AttestPage fetches the page again and compares its clean text with the baseline. It answers `unchanged`, `changed`, `gone` or `unreadable`, lists the fields that differ, and returns a signed receipt that names both the old and the new hash.

This guide runs the call with `curl` and `jq` against `https://vehcdj664efetfrsolne5umanq.srv.us`, then shows the same call as an MCP tool. For every field and error, see [Re-check a page](/docs/recheck).

## What the recheck does

- **Fetches the page again.** It fetches the URL in the baseline, following redirects again, and extracts the clean text the same way as the first time.
- **Compares byte for byte.** `content_sha256` is the hash of the clean text. Markup-only changes leave it the same. A page with a date, a counter or rotating text reads as changed on every visit.
- **Lists what differs.** `differences` names each compared field that is not the same, such as `content_sha256`, `http_status` or `final_url`.
- **Signs a receipt.** The new receipt is itself a baseline: send it in the next call to build a chain.
- **Stores nothing and calls nobody.** There is no schedule and no webhook. You call when you want to know.

## Price

US$0.003 per call, paid in USDC with x402 v2 on Base mainnet (real USDC). No account, key or sign-up. A request with a bad baseline gets 400 before payment and is never charged. Once the page is fetched, the call is charged even when the answer is `gone` or `unreadable`, because the fetch was done. All prices: [pricing.json](https://vehcdj664efetfrsolne5umanq.srv.us/pricing.json).

## 1. See an answer for free

The free sample rechecks the demo page against its own hash, so it reads `unchanged`.

```sh
curl -s https://vehcdj664efetfrsolne5umanq.srv.us/v1/sample/recheck | jq '{change, changed, differences, content_sha256: .page.content_sha256}'
```

```json
{
  "change": "unchanged",
  "changed": false,
  "differences": [],
  "content_sha256": "0e429607fdb16c005ef662414e758c53edb82e1cb24c3cbec239e4c1d6a7dfa0"
}
```

## 2. Read the price from the 402 offer

Step 3 explains the body. A request with a valid body gets the payment offer without being charged. The `PAYMENT-REQUIRED` header is base64 JSON:

```sh
curl -si -X POST https://vehcdj664efetfrsolne5umanq.srv.us/v1/recheck -H 'content-type: application/json' \
  -d '{ "url": "https://vehcdj664efetfrsolne5umanq.srv.us/v1/sample/page", "content_sha256": "0e429607fdb16c005ef662414e758c53edb82e1cb24c3cbec239e4c1d6a7dfa0" }' \
  | grep -i '^payment-required:' | cut -d' ' -f2 | tr -d '\r' | base64 -d \
  | jq '.accepts[0] | {scheme, network, amount, payTo}'
```

`amount` is in USDC base units (6 decimals), so `3000` is US$0.003.

## 3. Recheck the page

Send exactly one of two baselines:

- `receipt`: the compact receipt from an earlier call to this service (`/v1/fetch`, `/v1/verify/quote` or `/v1/recheck`, paid or trial; a sample receipt is not accepted).
- `url` and `content_sha256`: the `page.content_sha256` from our own fetch of that URL. A hash from another tool will not match.

Add `"return_text": true` to also get up to 20,000 characters of the new clean text. This body uses the demo page and its hash:

```sh
cat > body.json <<'EOF'
{ "url": "https://vehcdj664efetfrsolne5umanq.srv.us/v1/sample/page", "content_sha256": "0e429607fdb16c005ef662414e758c53edb82e1cb24c3cbec239e4c1d6a7dfa0" }
EOF
```

Pay with any x402 v2 client: it reads the offer from step 2, signs it and sends the same request again with a `PAYMENT-SIGNATURE` header. [One x402 payment step by step](/docs/examples/fetch-x402) shows this with plain `fetch`, and the [MCP server](/docs/mcp) does it for you. Save the answer as `answer.json`.

## 4. Read the answer

```sh
jq '{change, changed, differences, elapsed_seconds, advice}' answer.json
```

| `change` | What it means |
|---|---|
| `unchanged` | The clean text is the same as in the baseline. |
| `changed` | The text differs. Fetch the page again or check your quote before you rely on it. |
| `gone` | The page no longer exists: 404, 410, or the site's name no longer resolves. If the baseline was already gone, the answer is `unchanged`, and `advice` says the page was gone then and is still gone. |
| `unreadable` | We could not read the page this time, so we cannot say whether it changed. `page.content_kind` says why. Try again later. |

`elapsed_seconds` is the time since the baseline was fetched. It is `null` when you sent a URL and hash.

## 5. Keep the receipt and chain it

The `receipt` field is a compact JWS. Check it with the free verify route:

```sh
jq '{receipt}' answer.json \
  | curl -s -X POST https://vehcdj664efetfrsolne5umanq.srv.us/v1/receipt/verify -H 'content-type: application/json' -d @- | jq .valid
```

For the next recheck, send this receipt as `receipt` instead of the URL and hash. Its `baseline.receipt_sha256` is the SHA-256 of the receipt you sent, which links the chain.

## With MCP

The same call is the MCP tool `attestpage_recheck`, with the body from step 3 as its arguments. To use it from an MCP client with nothing to install, add the remote endpoint:

```json
{
  "mcpServers": {
    "attestpage": { "type": "http", "url": "https://vehcdj664efetfrsolne5umanq.srv.us/mcp" }
  }
}
```

One call to the remote endpoint with `curl`. `_meta["attestpage/trial"]` set to `false` asks for the payment offer rather than a trial call, so nothing is charged:

```sh
curl -s -X POST https://vehcdj664efetfrsolne5umanq.srv.us/mcp -H 'content-type: application/json' -d @- <<'EOF' \
  | jq '.result.structuredContent.accepts[0] | {scheme, network, amount}'
{ "jsonrpc": "2.0", "id": 1, "method": "tools/call",
  "params": { "name": "attestpage_recheck",
    "arguments": { "url": "https://vehcdj664efetfrsolne5umanq.srv.us/v1/sample/page", "content_sha256": "0e429607fdb16c005ef662414e758c53edb82e1cb24c3cbec239e4c1d6a7dfa0" },
    "_meta": { "attestpage/trial": false } } }
EOF
```

```json
{
  "scheme": "exact",
  "network": "eip155:8453",
  "amount": "3000"
}
```

The result has `isError: true` and the x402 payment requirements in `structuredContent`, with the same `amount` as step 2. Sign one of `accepts`, put the payload in `_meta["x402/payment"]` and call again: `structuredContent` is then the same JSON as `answer.json`.

## Questions

### How much does a recheck cost?

US$0.003 per call, one page per call. Checking one page every day for 30 days takes 30 calls.

### Is a recheck charged if the page is gone?

Yes. When the page was fetched, the call is charged and the answer is `gone` or `unreadable`. A bad baseline or a body that fails validation is a 400 before payment and is never charged.

### Does `unchanged` mean nothing on the page moved?

No. It means the clean text is the same byte for byte. Markup, scripts and images can still differ, and `differences` shows `raw_sha256` when the raw bytes moved.
