# The verify tool

Verify MCP exposes one tool.

```
verify_mintall_certificate(page_url)
```

It asks Mintall's backend to fetch the page and verify the certificate found
on it. The signature, domain, product, and URL-binding checks all run server
side. The caller never handles the JWT.

## Arguments

| Argument   | Type   | Notes                                 |
| ---------- | ------ | ------------------------------------- |
| `page_url` | string | Required. The product page to verify. |

## The result

A verified page:

```json
{
  "verified": true,
  "reason": "verified",
  "status": "verified",
  "pageUrl": "https://store.example/products/everyday-tote",
  "finalUrl": "https://store.example/products/everyday-tote",
  "issuedTo": "store.example",
  "snapshotAt": "2026-09-09T08:30:00+00:00",
  "canonicalSource": "https://api.mintall.ai/mc4p/products/7b2a9c14-4d31-4a0e-9f55-2c8e6b1a0d47",
  "checks": {
    "domainKnown": true,
    "domainVerified": true,
    "boundToUrl": true,
    "boundToDomain": true,
    "productIdMatches": true,
    "signatureValid": true,
    "certificateIntegrity": true,
    "timestampValid": true,
    "trustDataCurrent": true
  },
  "warnings": [],
  "errors": []
}
```

A page that names a Mintall product but makes no signed claim:

```json
{
  "verified": false,
  "reason": "unverified",
  "status": "unverified",
  "pageUrl": "https://store.example/products/everyday-tote",
  "finalUrl": "https://store.example/products/everyday-tote",
  "issuedTo": "store.example",
  "snapshotAt": "2026-09-09T08:30:00+00:00",
  "canonicalSource": "https://api.mintall.ai/mc4p/products/7b2a9c14-4d31-4a0e-9f55-2c8e6b1a0d47",
  "checks": {
    "domainKnown": true,
    "domainVerified": true,
    "boundToUrl": true,
    "boundToDomain": true,
    "productIdMatches": true,
    "signatureValid": null,
    "certificateIntegrity": null,
    "timestampValid": null,
    "trustDataCurrent": true
  },
  "warnings": [
    "This page identifies itself as a Mintall-tracked product but carries no signed trust claim. Nothing here failed a check. The absence of a claim is not evidence of a problem."
  ],
  "errors": []
}
```

### Fields

| Field             | Meaning                                                                                                             |
| ----------------- | ------------------------------------------------------------------------------------------------------------------- |
| `verified`        | `true` only when `reason` is `verified`. The one field to branch on.                                                |
| `reason`          | The verdict, always present. The ten values are listed below.                                                       |
| `status`          | Mintall's document status: `verified`, `failed`, or `unverified`. `null` when the check never reached the registry. |
| `pageUrl`         | The URL you submitted.                                                                                              |
| `finalUrl`        | Where the fetch landed after redirects. This is what the checks ran against.                                        |
| `issuedTo`        | The domain the certificate was issued to.                                                                           |
| `snapshotAt`      | When the merchant last published trust data to the page.                                                            |
| `canonicalSource` | The registry URL the page's certificate points back to.                                                             |
| `checks`          | The per-check map, passed through unchanged. `null` when no certificate was read.                                   |
| `warnings`        | Sentences an agent can act on. Empty on a clean verify.                                                             |
| `errors`          | Why the check could not complete. Empty unless the fetch failed.                                                    |

`verified: true` means the certificate is authentic, unaltered, and bound to
this exact page. Nothing weaker.

## Verdicts

Four verdicts come from Mintall's answer about the document on the page:

| `reason`              | Meaning                                                            |
| --------------------- | ------------------------------------------------------------------ |
| `verified`            | The page carries a signed certificate and every check passed.      |
| `unverified`          | The page identifies a Mintall product but carries no signed claim. |
| `certificate_expired` | The signature is authentic, past its 7 day window.                 |
| `checks_failed`       | A signed certificate, and a check did not pass.                    |

Six come from the fetch itself, decided without asking the registry:

| `reason`              | Meaning                                                       |
| --------------------- | ------------------------------------------------------------- |
| `no_certificate`      | No Mintall node on the page.                                  |
| `invalid_certificate` | A node is present, its `canonicalSource` is unusable.         |
| `canonical_mismatch`  | The `canonicalSource` names a registry that is not Mintall's. |
| `product_deleted`     | The named product is not in the registry.                     |
| `password_protected`  | The fetch landed on a storefront password gate.               |
| `page_fetch_failed`   | Blocked, timed out, too large, or non-2xx.                    |

**Three of these are not failures:** `no_certificate` and `unverified` both mean the page carries no signed claim.
  `certificate_expired` means the signature is authentic and the page is out of
  sync. An agent that renders any of the three as a warning about the merchant
  is misreporting it.

## Reading the checks

`checks` is the same map the [verify endpoint](/api/verifying#reading-the-checks)
returns. Six entries are load bearing, three are advisory, and every entry is
nullable.

`null` means the check did not run for this request. In the `unverified`
example above, the three signature checks are `null` because there was no
signature to check. That is not the same as a check that ran and failed.

`boundToUrl` is the anti-copy check. A certificate lifted onto another listing
still carries the URL it was issued for, so it fails here without anyone
needing to trust the page.

## Freshness and limits

Every call refetches the page. There is no cached tier, so a certificate the
merchant published a minute ago shows up.

That makes calls more expensive than a cached
[page check](/api/page-checks#cached-and-fresh), and they are rate limited per
caller. Past the limit the tool returns an error rather than a verdict.

## Errors

A verdict and an error are different outcomes. Every verdict above describes
something true about the page. An error means the check could not be completed
at all: Mintall was unreachable, or the request was rate limited.

Branch on `verified` for the verdict. Handle a tool error as a retry, not as a
statement about the merchant.