# Re-check a page against an earlier receipt

Last updated: 2026-10-12

`POST /v1/recheck` fetches the page named in an earlier receipt again and tells you whether its text changed: `unchanged`, `changed`, `gone` or `unreadable`, the fields that differ, and a signed receipt naming both the old and the new hashes. Price: US$0.003 per call.

## When to use it

- For page change detection without storing anything: keep the receipt, recheck when you need to know.
- Before reusing a quote or a citation you checked days ago.
- To keep a dated chain of evidence that a page stayed the same (each receipt names the one before).

## Request

Send exactly one of the two baseline forms. The receipt from an earlier call:

```json
{ "receipt": "eyJhbGciOiJFZERTQSIs…", "return_text": false }
```

Or a URL and the `content_sha256` from our own fetch of it:

```json
{ "url": "https://www.iana.org/help/example-domains", "content_sha256": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", "return_text": false }
```

| Field | Required | Meaning |
|---|---|---|
| `receipt` | one of the two forms | compact JWS receipt from an earlier `/v1/fetch`, `/v1/verify/quote` or `/v1/recheck` call of this service, paid or trial (not a sample), at most 160 KB |
| `url` | one of the two forms | only without `receipt`: http or https URL, at most 2,048 characters |
| `content_sha256` | with `url` | the `page.content_sha256` from our own fetch, 64 hex characters; other tools hash other text, so their hashes will not match |
| `return_text` | no | also return up to 20,000 characters of the new clean text; default `false` |

The page fetched is the baseline's `url` (the URL first asked for, not the final URL), so redirects are followed again. The body may be up to 168 KB, so a long receipt fits.

## Answer

From the free sample (`GET /v1/sample/recheck`), shortened:

```json
{
  "change": "unchanged",
  "changed": false,
  "differences": [],
  "baseline": {
    "source": "caller",
    "receipt_sha256": null,
    "url": "https://vehcdj664efetfrsolne5umanq.srv.us/v1/sample/page",
    "content_sha256": "0e429607…"
  },
  "elapsed_seconds": null,
  "page": {
    "final_url": "https://vehcdj664efetfrsolne5umanq.srv.us/v1/sample/page",
    "http_status": 200,
    "content_kind": "real",
    "content_sha256": "0e429607…",
    "raw_sha256": "179b9ac4…"
  },
  "text": null,
  "injection_flags": [],
  "advice": "The page's text is the same as in the baseline (byte for byte on the clean text). Markup or other bytes may still have moved; see differences.",
  "receipt": "eyJhbGciOiJFZERTQSIs…",
  "tier": "paid",
  "rail": "x402",
  "network": "eip155:8453"
}
```

| `change` | `changed` | Meaning |
|---|---|---|
| `unchanged` | `false` | The page's text is the same as in the baseline. A page already gone in the baseline and still gone is unchanged too. |
| `changed` | `true` | The page's text differs from the baseline. Fetch it again or check your quote before you rely on it. |
| `gone` | `true` | The page no longer exists (404 or 410, or the site's name no longer resolves). |
| `unreadable` | `null` | We could not read the page this time (`page.content_kind` says why), so we cannot say whether it changed. Try again later. |

- `differences` lists every compared field that differs, whatever the verdict: `content_sha256`, `raw_sha256`, `http_status`, `final_url`, `content_kind`, and with a receipt baseline also `server_ip` and `tls.cert_sha256` when both sides have them.
- `baseline` is what was compared against. With the `url` form, `source` is `caller` and the fields only a receipt carries are null.
- `elapsed_seconds` is the time since the baseline was fetched (null with the `url` form).
- `page`, `text` and `injection_flags` are the new fetch, as [`/v1/fetch`](/docs/fetch) gives them.

## What "changed" means

The comparison is byte for byte on the clean text we extract (`content_sha256`). Markup-only changes are not changes: `raw_sha256` may differ while the answer is `unchanged`. A page with a date, a counter or rotating text reads as changed on every visit. A `content_sha256` from another tool will not match ours: use the hash from our own fetch.

## Chaining

The recheck receipt is itself a valid baseline: send it to the next call. Its `result.baseline.receipt_sha256` is the SHA-256 of the receipt you sent, so a chain can be checked offline with [verify-receipt.mjs](/docs/receipt-verify).

## Charges and errors

The call is charged like `/v1/fetch` whenever it answers, `gone` and `unreadable` included: the fetch was done and the receipt is evidence of it. Every baseline problem is a 400 before payment, never charged:

- `bad_request`: neither or both baseline forms, or `content_sha256` without `url`.
- `baseline_invalid`: the receipt does not verify against this service's keys, is not a fetch, verify/quote or recheck receipt, is a sample, or names no URL; `details.reason` says which.

The other errors are those of `/v1/fetch`; see [Errors](/docs/errors). On the edge, a PDF page answers 501 `not_on_edge`, uncharged.

## Compared with a hosted watch

No schedule, no webhook, nothing stored: you call when you want to know, and pay US$0.003 per check.
