> ## Documentation Index
> Fetch the complete documentation index at: https://docs.shopsniffer.com/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# Pay per request with x402

Tutorial — fund a wallet, handle your first 402 Payment Required, sign the payment, and retry successfully. No account, no API key.

## Overview

This tutorial takes you from "I want to call ShopSniffer from an autonomous agent with no account" to "I have a completed report". We'll fund a Base-network wallet with USDC, trigger a `402 Payment Required` response, sign the payment, and retry successfully. The end state: a working x402-paid request and a reusable pattern for the rest of your agent.

**You'll need:**

- A Node.js or Python environment (examples in both)
- A wallet with ~$11 of USDC on the Base network (we'll cover getting there)
- `x402-client` (Node) or `x402-py` (Python) — the official helper libraries

x402 is an open protocol that revives HTTP 402. A server responds `402 Payment Required` with on-chain payment instructions; the client pays and retries. ShopSniffer implements x402 only on `POST /api/jobs` — read endpoints are free. See [x402 payment](/x402-payment) for the protocol reference.

## Step 1 — get USDC on Base

You need a small amount of USDC on the [Base](https://base.org) network — specifically on the official [Base USDC contract](https://basescan.org/address/0x833589fcd6edb6e08f4c7c32d4f71b54bda02913). Each job costs exactly $9.99 USDC; top up to ~$11 to cover fees and one retry.

Easiest path:

**Create or use an EVM wallet**

MetaMask, Rabby, or any wallet that supports Base. If you're going fully automated, generate a fresh private key — x402 works great with ephemeral wallets.
  **Fund with USDC on Base**

Options:
    - **Bridge from Ethereum** via the [Base Bridge](https://bridge.base.org) (takes a few minutes, gas required on mainnet)
    - **Fund via Coinbase** — Coinbase supports direct withdrawals to Base for USDC with no bridge step
    - **Cross-chain swap** via Across, LiFi, Squid, or any bridge aggregator
  **Verify the balance**

Open [basescan.org](https://basescan.org) and paste your address. Confirm you see `USD Coin (USDC)` with your balance. If it shows 0, your USDC is on the wrong network.

Don't send USDC from a chain ShopSniffer doesn't accept and expect it to work. The server verifies on-chain settlement on Base specifically. If you pay on Arbitrum, Polygon, or Ethereum L1, the payment proof will fail verification and your request will be rejected.

## Step 2 — trigger a 402

First, let's see the 402 response with a naive request that has no auth:

```bash
curl -v -X POST https://shopsniffer.com/api/jobs \
  -H "Content-Type: application/json" \
  -d '{"domain": "allbirds.com"}'
```

You'll get back:

```http
HTTP/1.1 402 Payment Required
Content-Type: application/json
```

```json
{
  "error": "Payment Required",
  "x402": {
    "version": "1",
    "accepts": [
      {
        "scheme": "exact",
        "network": "base",
        "maxAmountRequired": "9990000",
        "resource": "https://shopsniffer.com/api/jobs",
        "payTo": "0x767131d92c41D56546eC72fecD0F1d63900fa9D9",
        "asset": "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913",
        "description": "Create a Shopify store analysis report…"
      }
    ]
  }
}
```

Key fields:

| Field | Meaning |
| --- | --- |
| `maxAmountRequired` | 9,990,000 smallest USDC units = $9.99 (USDC has 6 decimals) |
| `payTo` | Where to send the payment on Base |
| `asset` | Base USDC contract (verify this before paying!) |
| `network` | Must be `base` |

## Step 3 — pay and retry

The manual way involves constructing an EIP-3009 `transferWithAuthorization` signature. Don't do that by hand — use an official helper library.

**Node.js (x402-client)**

```typescript
    import { withX402Payment } from "x402-client";
    import { privateKeyToAccount } from "viem/accounts";

    // Ephemeral wallet — replace with your own private key management
    const account = privateKeyToAccount(
      process.env.WALLET_PRIVATE_KEY as `0x${string}`,
    );

    async function createJob(domain: string) {
      const res = await withX402Payment(
        "https://shopsniffer.com/api/jobs",
        {
          method: "POST",
          headers: { "Content-Type": "application/json" },
          body: JSON.stringify({ domain }),
        },
        account,
      );

      if (!res.ok) {
        const err = await res.text();
        throw new Error(`Job creation failed: ${res.status} ${err}`);
      }

      const { job } = await res.json();
      console.log(`Created job ${job.id}`);
      return job;
    }

    await createJob("allbirds.com");
    ```
  **Python (x402-py)**

```python
    from x402 import X402Client
    from eth_account import Account
    import os, requests

    account = Account.from_key(os.environ["WALLET_PRIVATE_KEY"])
    client = X402Client(account=account)

    def create_job(domain: str):
        res = client.request(
            "POST",
            "https://shopsniffer.com/api/jobs",
            json={"domain": domain},
        )
        res.raise_for_status()
        job = res.json()["job"]
        print(f"Created job {job['id']}")
        return job

    create_job("allbirds.com")
    ```
  **Manual (cURL + signer)**

```bash
    # 1. Get the 402 response
    RESP=$(curl -s -X POST https://shopsniffer.com/api/jobs \
      -H "Content-Type: application/json" \
      -d '{"domain": "allbirds.com"}')

    # 2. Extract payTo, asset, maxAmountRequired
    PAY_TO=$(echo "$RESP" | jq -r '.x402.accepts[0].payTo')
    ASSET=$(echo "$RESP" | jq -r '.x402.accepts[0].asset')
    AMOUNT=$(echo "$RESP" | jq -r '.x402.accepts[0].maxAmountRequired')

    # 3. Sign EIP-3009 transferWithAuthorization (use cast, foundry, or ethers)
    PROOF=$(cast tx-sign ...)  # beyond the scope of this tutorial

    # 4. Retry with X-PAYMENT header
    curl -X POST https://shopsniffer.com/api/jobs \
      -H "Content-Type: application/json" \
      -H "X-PAYMENT: $PROOF" \
      -d '{"domain": "allbirds.com"}'
    ```

    This is educational — in production use the helper libraries.

## Step 4 — verify success

A successful x402-paid request returns the normal job creation response:

```json
{
  "job": {
    "id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
    "domain": "allbirds.com",
    "slug": "allbirds-com",
    "status": "pending",
    "payment_tx_hash": "0x…",
    "payment_sender": "0xYourWallet…"
  }
}
```

The `payment_tx_hash` and `payment_sender` fields are your receipt — they record which on-chain transaction paid for which job. Keep them if you need auditing.

From here it's identical to any authenticated job — poll status, subscribe to the WebSocket, fetch the report. See the [jobs API](/api/jobs) for the full lifecycle.

## Debugging

Things that go wrong, and how to fix them:

**Still getting 402 after retrying**

Your `X-PAYMENT` header is malformed or the on-chain transaction hasn't settled yet. Wait 10-15 seconds and retry once. If it's still failing, check:
    - You're using the Base network (chainId 8453), not Ethereum
    - The USDC asset address matches the one in the 402 response exactly
    - `maxAmountRequired` is exactly $9.99 — don't underpay

  **Insufficient funds**

Confirm USDC balance on [basescan.org](https://basescan.org) for your wallet address. You also need a small amount of ETH on Base for gas — even EIP-3009 sponsored payments may require a few cents of ETH depending on the client library.

  **Payment sent but request still fails**

Check the transaction on basescan. If it's `Success`, the issue is your `X-PAYMENT` header encoding — the helper libraries handle this but a hand-rolled encoder might produce the wrong signature digest. Use the official client.

  **I paid but got a 500 error**

This is rare — it means the on-chain settlement succeeded but our verification pipeline hit an error. Save the `tx_hash` and [contact support](https://shopsniffer.com/support) with the transaction hash. We'll either credit a job or refund the USDC.

## When to use x402 vs API keys

| Situation | Use |
| --- | --- |
| Long-running server integration, predictable usage | API key |
| Autonomous agent spinning up per-task | x402 |
| One-shot scripts that don't want credential management | x402 |
| High-volume daily usage | Pro Monthly subscription (Stripe) |
| CI pipeline running on every PR | API key |

x402 shines when you want zero credential lifecycle management. For steady-state usage, API keys are simpler and cheaper (no gas, no on-chain latency).

## Next steps

**[x402 payment reference](/x402-payment)**

Protocol-level detail: fields, flow, network specifics.
  **[AI agent tutorial](/guides/ai-agent-python)**

Wire x402 into a real agent loop.
  **[Authentication](/authentication)**

Compare x402 with API keys and Better Auth sessions.
  **[Jobs API](/api/jobs)**

What to do with your new job ID.