Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.polygon.technology/llms.txt

Use this file to discover all available pages before exploring further.

This tutorial walks through setting up an x402 v2 buyer client on Polygon. By the end, your client will automatically detect 402 Payment Required responses, pay in USDC, and retrieve the unlocked resource.
Polygon facilitators on Amoy and mainnet run x402 v2. Use the @x402/* packages shown below. If you have an existing V1 integration, see Migration: V1 to V2.
This tutorial uses test credentials and local endpoints for clarity. In production, never expose private keys or facilitator URLs publicly.

Prerequisites

Before you begin, ensure you have:
  • A crypto wallet with USDC on Polygon Amoy (or mainnet for production)
  • Node.js 18+ with npm or Bun
  • A service that requires payment via x402, or a local seller from the Quickstart for Sellers
For Go or Python client examples, see the official x402 buyer quickstart.

Install dependencies

Install the x402 v2 client packages and viem for signing:
Wherever bun is used, replace it with npm or your preferred package manager.
bun install @x402/fetch @x402/core @x402/evm viem dotenv

Create a wallet signer

Create a signer from your private key. In x402 v2, the client selects the correct network from the 402 response; you do not bind a chain-specific wallet client.
import { privateKeyToAccount } from "viem/accounts";
import "dotenv/config";

const privateKey = process.env.EVM_PRIVATE_KEY;
if (!privateKey) throw new Error("EVM_PRIVATE_KEY not set in .env");

const signer = privateKeyToAccount(
  privateKey.startsWith("0x")
    ? (privateKey as `0x${string}`)
    : (`0x${privateKey}` as `0x${string}`)
);

console.log("Wallet address:", signer.address);
Fund this wallet with test USDC on Amoy before calling paid endpoints. See the Polygon faucet for test POL.

Make paid requests automatically

@x402/fetch extends the native fetch API to handle 402 responses and payment headers for you.
import { wrapFetchWithPayment } from "@x402/fetch";
import { x402Client, x402HTTPClient } from "@x402/core/client";
import { ExactEvmScheme } from "@x402/evm/exact/client";
import { privateKeyToAccount } from "viem/accounts";
import "dotenv/config";

const signer = privateKeyToAccount(
  process.env.EVM_PRIVATE_KEY as `0x${string}`
);

const client = new x402Client();
client.register("eip155:*", new ExactEvmScheme(signer));

const fetchWithPayment = wrapFetchWithPayment(fetch, client);

const RESOURCE_URL =
  process.env.RESOURCE_URL || "http://127.0.0.1:4021/weather";

(async () => {
  const response = await fetchWithPayment(RESOURCE_URL, { method: "GET" });
  const data = await response.json();
  console.log("Response:", data);

  if (response.ok) {
    const httpClient = new x402HTTPClient(client);
    const paymentResponse = httpClient.getPaymentSettleResponse((name) =>
      response.headers.get(name)
    );
    console.log("Payment settled:", paymentResponse);
  }
})();
The client:
  1. Sends the request
  2. Receives 402 Payment Required with payment requirements
  3. Pays in USDC via the seller’s facilitator (Polygon Amoy: https://x402-amoy.polygon.technology)
  4. Retries with a PAYMENT-SIGNATURE header
  5. Returns the unlocked response and a PAYMENT-RESPONSE receipt header

Payment schemes

Most Polygon endpoints use the exact scheme (fixed price per request). Servers may also advertise upto (usage-based) or batch-settlement (high-volume batched micropayments). Register the matching scheme when the server requires it. See x402 payment schemes.

Error handling

try {
  const response = await fetchWithPayment(url, { method: "GET" });
  // Handle success
} catch (error) {
  if (error instanceof Error && error.message.includes("No scheme registered")) {
    console.error("Network not supported: register the appropriate scheme");
  } else if (error instanceof Error && error.message.includes("Payment already attempted")) {
    console.error("Payment failed on retry");
  } else {
    console.error("Request failed:", error);
  }
}

Reference

Configuration, error codes, and guardrails.

Schema

nametyperequiredexampledescription
EVM_PRIVATE_KEYstringyes"abcd1..."Wallet key for signing payments
RESOURCE_URLstringyes"https://api.example.com/paid-endpoint"Target API URL
RESOURCE_BASE_URLstringoptional"http://127.0.0.1:4021"Base URL when using Axios
USDCtokenimpliedUSDC on PolygonPayment asset
The facilitator URL is configured on the seller side. Buyers do not set it directly; the 402 response includes payment requirements for the seller’s facilitator.

Errors

code / casemeaningfix
MISSING_CONFIGWallet or URL not setVerify .env keys
No scheme registeredClient missing scheme for networkRegister ExactEvmScheme with "eip155:*"
Payment already attemptedPayment failed on retryCheck wallet balance and facilitator health
402_LOOPAPI keeps returning 402Ensure seller uses x402 v2 and matching network (eip155:80002 or eip155:137)

Do / Don’t Do Guardrails

DoDon’t
Use @x402/fetch or @x402/axios with v2 packagesUse legacy x402-fetch or x402-axios against Polygon facilitators
Test on Amoy before mainnetHardcode private keys in scripts
Read receipts via x402HTTPClient.getPaymentSettleResponse()Parse PAYMENT-RESPONSE headers manually
Use wrapFetchWithPayment or wrapAxiosWithPaymentRe-implement 402 logic yourself

References