# For AI agents — x402-shop-scout

How an autonomous agent finds this service, pays for a call, and uses what comes back.

## 1. Discovery

Two machine-readable entry points, both free:

```bash
curl -s {BASE_URL}/.well-known/x402      # the manifest below
```

```jsonc
{
  "x402Version": 1,
  "name": "x402-shop-scout",
  "description": "Live marketplace intelligence over eBay Browse — listings search and is-this-a-deal verdicts",
  "resources": [
    {
      "resource": "GET /search",
      "description": "Search live marketplace listings with prices, shipping, condition and seller reputation.",
      "price": "$0.002",
      "accepts": [
        { "scheme": "exact", "network": "base-sepolia", "asset": "USDC", "payTo": "0x40252CFDF8B20Ed757D61ff157719F33Ec332402", "maxAmountRequired": "2000" },
        { "scheme": "exact", "network": "solana",       "asset": "USDC", "payTo": "WwwuGbqHrwF5RG89KhUbmRWEvjnRH9k5kVM5p7T3WwW", "maxAmountRequired": "2000" }
      ],
      "outputSchema": { /* … */ }
    }
    // …
  ]
}
```

And [`skill.md`](https://github.com/nirholas/x402-shop-scout/blob/main/skill.md) at the repo root — the prose contract written for a model to read directly: what each endpoint does, its price, its exact response shape, and the error codes. Drop it into your agent's context and it can call this service without any other documentation.

## 2. Paying

**Pay in USDC on Base or Solana — your client picks the rail.** Every 402 lists both:

| Rail | Network | Asset | payTo | Facilitator |
|---|---|---|---|---|
| EVM | `base-sepolia` / `base` | USDC `0x036CbD53842c5426634e7929541eC2318f3dCF7e` | `0x40252CFDF8B20Ed757D61ff157719F33Ec332402` | `https://x402.org/facilitator` |
| Solana | `solana` | USDC `EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v` | `WwwuGbqHrwF5RG89KhUbmRWEvjnRH9k5kVM5p7T3WwW` | `https://facilitator.payai.network` |

### EVM

The wallet signs an EIP-3009 transfer authorization entirely locally — no round-trip, no gas from the agent. With [`x402-fetch`](https://www.npmjs.com/package/x402-fetch) it's two lines:

```ts
import { privateKeyToAccount } from "viem/accounts";
import { wrapFetchWithPayment } from "x402-fetch";

const payFetch = wrapFetchWithPayment(fetch, privateKeyToAccount(process.env.PRIVATE_KEY as `0x${string}`));
const res = await payFetch("{BASE_URL}/search");   // 402 → pay → 200, transparently
```

### Solana

Solana wallets sign serialized transactions, so the server builds one for you:

```
POST {BASE_URL}/api/x402-checkout?action=prepare
  { "accept": <solana entry from the 402>, "buyer": "<base58 pubkey>" }
  → { "tx_base64", "recent_blockhash" }

POST {BASE_URL}/api/x402-checkout?action=encode
  { "accept": <same>, "signed_tx_base64": "<signed>", "resource_url": "<resource>" }
  → { "x_payment" }
```

Retry the original request with `X-PAYMENT: <x_payment>`. The `extra.feePayer` sponsor covers the SOL network fee, so the agent's wallet needs only USDC.

### What the 402 tells you

Each entry in `accepts[]` carries an `outputSchema` describing the route it guards:

```jsonc
"outputSchema": {
  "input":  { "type": "http", "method": "GET", "queryParams": { "q": { "type": "string" } } },
  "output": { "type": "object", "properties": { "listings": { "type": "array" } } }
}
```

`input` is how to call the route, `output` is the shape of the 200 body. Both are generated from
[`openapi.json`](https://github.com/nirholas/x402-shop-scout/blob/main/openapi.json), so a client that only
ever sees a 402 can still invoke the endpoint correctly and parse what comes back. Both rails carry
the same schema.

### Protocol version

This service speaks **x402 v1**: the challenge is `{ x402Version: 1, error, accepts[] }`, which is
what the `x402-fetch` clients in [`examples/`](https://github.com/nirholas/x402-shop-scout/tree/main/examples)
and every current wallet integration expect. x402 v2 — CAIP-2 network ids and
`extensions.bazaar.schema` instead of `outputSchema` — is a future upgrade for agentcash
compatibility; it changes the challenge shape, so it will land as a deliberate version bump rather
than silently.

## 3. What you get back

A `200` whose body **is** the artifact — every paid route in this service returns what you bought inline. No job ids, no polling, no webhooks. Alongside it:

- `X-PAYMENT-RESPONSE` header — base64 JSON settlement receipt
- `payment` field in the body — the same receipt, for agents that only parse JSON

```json
{ "success": true, "rail": "solana", "network": "solana", "transaction": "5xk…", "payer": "9wF…", "amount": "2000" }
```

Persist it — it's the audit trail linking a spend to the data it bought.

## 4. Budgeting

- `GET /search` → **$0.002**
- `GET /deal-check/:itemId` → **$0.002**

Both routes are `$0.002`. A realistic "find and grade" loop is one search plus a deal-check on the top few candidates — four calls, $0.008. 1,000 deal-checks cost $2.

## 5. MCP integration

[`examples/mcp-tool.md`](https://github.com/nirholas/x402-shop-scout/blob/main/examples/mcp-tool.md) has a complete MCP server exposing these 2 endpoints as tools for Claude, with the payment wrapper already wired in.

## 6. Listing this service

Once deployed at a public origin (set `PUBLIC_BASE_URL` so the 402 `resource` is correct):

- **[x402scan.com](https://x402scan.com)** — crawls `/.well-known/x402`; submit your base URL.
- **x402 Bazaar** — the protocol's own directory, reachable through the facilitator's `list` API; see <https://x402.org>.
- **[agentic.market](https://agentic.market)** — agent-facing marketplace; the manifest plus `skill.md` is all it needs.

All three read the same manifest this repo already serves, so listing is a URL submission, not an integration.

## 7. Data honesty

Live eBay data is used when `EBAY_CLIENT_ID` + `EBAY_CLIENT_SECRET` (or a raw `EBAY_OAUTH_TOKEN`) are set — a free developer account at developer.ebay.com. Without them the service answers from a deterministic fixture marketplace of 15 listings across five product families and labels every response `"source": "fixture"`. The verdict logic is identical in both modes; only the listing corpus changes.

An agent should branch on the `source` field rather than assume live data.
