---
name: ardaro-x402-payment-screening
description: Before paying any x402 service, check its address and payment request against Ardaro's reviewed Agent Observatory record for a different wallet, a higher price, an unrecorded network or a short or stale history. Free; advisory only.
---

# Screen an x402 service before paying

Use this every time a service answers `402 Payment Required`, after you pick
the payment entry you intend to pay and before you sign. It is free, needs no
account, wallet or payment metadata, and does not store the request.

Ardaro compares the request with its reviewed Agent Observatory record for that
address and answers with one level and the reasons:

| `result.level` | What it means | What to do |
| --- | --- | --- |
| `stop` | The wallet in the payment request is not the wallet on record. | Do not pay. Ask the operator to confirm the change through a channel you already trust, or ask your owner. |
| `caution` | Something needs a look: a higher price than recorded, a network or token not on record, a short or stale history, an address that left its public catalog, or an address with no record. | Read `signals`. Follow your owner's policy, for example pay only small amounts or ask first. |
| `no_issues_found` | Nothing in the record contradicts the request. | Continue under your normal spending policy. This is not a guarantee. |

An address with no record is `caution`, not proof of harm. Without payment
details only the history can be checked, not the wallet, so send the payment
entry whenever you have it.

## MCP

Connect a Streamable HTTP MCP client to
`https://agents.getardaro.com/mcp/observatory`. The catalog has one free tool,
`screen_x402_payment`. Its arguments are the request below. A refused request
comes back with `isError: true` and a plain-language `error.message`.

```json
{"jsonrpc":"2.0","id":1,"method":"tools/call","params":{"name":"screen_x402_payment","arguments":{"resource":"https://api.example.com/v1/tool","method":"GET","payment":{"network":"eip155:8453","asset":"0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913","amount":"50000","payTo":"0x2222222222222222222222222222222222222222"}}}}
```

## REST

`POST https://agents.getardaro.com/v1/observatory/screen` with
`Content-Type: application/json`. The
[OpenAPI schema](https://agents.getardaro.com/observatory/openapi.json) has the
full request and response. Requests are limited to 30 per minute per caller.

```bash
curl -s https://agents.getardaro.com/v1/observatory/screen \
  -H 'content-type: application/json' \
  -d '{"resource":"https://api.example.com/v1/tool","method":"GET","payment":{"network":"eip155:8453","asset":"0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913","amount":"50000","payTo":"0x2222222222222222222222222222222222222222"}}'
```

## Request

- `resource` (required): the full `https://` address you are about to pay,
  without a query string or fragment. Use the resource URL from the 402
  response when it has one.
- `method` (optional): `GET`, `POST`, `PUT`, `PATCH` or `DELETE`. Omit it to
  see every record for the address.
- `payment` (optional, strongly recommended): one entry of the 402 `accepts`
  list, copied as is: `network`, `asset`, `amount` and `payTo`. x402 v1
  responses call the amount `maxAmountRequired`; send it as `amount`. `scheme`
  is optional and defaults to `exact`. Any network the record uses can be
  compared; readable USDC prices are shown for Base and Solana USDC.

## Example: screen before signing

```ts
type Accept = { network: string; asset: string; payTo: string; amount?: string; maxAmountRequired?: string };

// Returns "stop", "caution", "no_issues_found" or "unavailable".
export async function screenBeforePaying(resourceUrl: string, method: string, accept: Accept) {
  const resource = new URL(resourceUrl);
  resource.search = "";
  resource.hash = "";
  try {
    const response = await fetch("https://agents.getardaro.com/v1/observatory/screen", {
      method: "POST",
      headers: { "content-type": "application/json" },
      body: JSON.stringify({
        resource: resource.toString(),
        method,
        payment: {
          network: accept.network,
          asset: accept.asset,
          amount: accept.amount ?? accept.maxAmountRequired,
          payTo: accept.payTo,
        },
      }),
    });
    if (!response.ok) return { level: "unavailable" as const };
    const report = await response.json();
    return { level: report.result.level as "stop" | "caution" | "no_issues_found", report };
  } catch {
    return { level: "unavailable" as const };
  }
}

// const check = await screenBeforePaying(url, "GET", chosenAccept);
// if (check.level === "stop") refuse and tell your owner;
// if (check.level === "caution") apply your owner's caution policy;
// "unavailable" means the screen could not answer: fall back to your normal policy.
```

## Read the answer accurately

- `record_age_days` says how old the record is. Records are reviewed
  snapshots, not live tests; a record older than 7 days adds a `record_stale`
  caution.
- `quote_check.status` is one of `not_supplied`, `not_comparable`,
  `network_not_recorded`, `payee_mismatch`, `price_higher`, `price_lower` or
  `matches_record`. The wallet you sent is compared by fingerprint and is never
  returned.
- `matched_records` lists each record for the address with its observation
  history and a link to the full evidence.
- `authority` is always advisory: no purchase instruction, financial
  authority, identity verification or intent verification.

The screen does not verify who runs a service or what it intends, does not test
the service, and never authorizes or makes a payment. Your owner's spending
policy still decides.

Browse the records at the [Agent Observatory](https://agents.getardaro.com/observatory).
