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 for the protocol reference.

Step 1 — get USDC on Base

You need a small amount of USDC on the Base network — specifically on the official Base USDC contract. Each job costs exactly $9.99 USDC; top up to ~$11 to cover fees and one retry.

Easiest path:

1

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.

2

Fund with USDC on Base

Options:

  • Bridge from Ethereum via the Base Bridge (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
3

Verify the balance

Open 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:

FieldMeaning
maxAmountRequired9,990,000 smallest USDC units = $9.99 (USDC has 6 decimals)
payToWhere to send the payment on Base
assetBase USDC contract (verify this before paying!)
networkMust 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.

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");

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 for the full lifecycle.

Debugging

Things that go wrong, and how to fix them:

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

Confirm USDC balance on 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.

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.

This is rare — it means the on-chain settlement succeeded but our verification pipeline hit an error. Save the tx_hash and contact support with the transaction hash. We'll either credit a job or refund the USDC.

When to use x402 vs API keys

SituationUse
Long-running server integration, predictable usageAPI key
Autonomous agent spinning up per-taskx402
One-shot scripts that don't want credential managementx402
High-volume daily usagePro Monthly subscription (Stripe)
CI pipeline running on every PRAPI 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

Protocol-level detail: fields, flow, network specifics.

Learn More
AI agent tutorial

Wire x402 into a real agent loop.

Learn More
Authentication

Compare x402 with API keys and Better Auth sessions.

Learn More
Jobs API

What to do with your new job ID.

Learn More
Ask a question... ⌘I