> ## 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.

# x402 Quickstart for Buyers

> Tutorial: set up an x402 v2 buyer client on Polygon to automatically pay for and access paywalled API endpoints.

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.

<Note>
  Polygon facilitators on [Amoy](https://x402-amoy.polygon.technology) and
  [mainnet](https://x402.polygon.technology) run **x402 v2**. Use the `@x402/*`
  packages shown below. If you have an existing V1 integration, see
  [Migration: V1 to V2](./migration-v1-to-v2.mdx).
</Note>

<Warning title="Security notice">
  This tutorial uses test credentials and local endpoints for clarity.
  In production, never expose private keys or facilitator URLs publicly.
</Warning>

## Prerequisites

Before you begin, ensure you have:

* A crypto wallet with USDC on Polygon Amoy (or mainnet for production)
* [Node.js](https://nodejs.org/en) 18+ with npm or [Bun](https://bun.sh/)
* A service that requires payment via x402, or a local seller from the [Quickstart for Sellers](./quickstart-sellers.mdx)

For Go or Python client examples, see the [official x402 buyer quickstart](https://docs.x402.org/getting-started/quickstart-for-buyers).

## Install dependencies

Install the x402 v2 client packages and [viem](https://viem.sh/) for signing:

> Wherever `bun` is used, replace it with `npm` or your preferred package manager.

<Tabs>
  <Tab title="Fetch">
    ```bash theme={null}
    bun install @x402/fetch @x402/core @x402/evm viem dotenv
    ```
  </Tab>

  <Tab title="Axios">
    ```bash theme={null}
    bun install @x402/axios @x402/core @x402/evm axios viem dotenv
    ```
  </Tab>
</Tabs>

## 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.

```ts theme={null}
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](/tools/gas/matic-faucet/) for test POL.

## Make paid requests automatically

<Tabs>
  <Tab title="Fetch">
    `@x402/fetch` extends the native `fetch` API to handle 402 responses and
    payment headers for you.

    ```ts theme={null}
    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);
      }
    })();
    ```
  </Tab>

  <Tab title="Axios">
    `@x402/axios` adds a payment interceptor to Axios so requests retry with
    payment headers automatically.

    ```ts theme={null}
    import { x402Client, wrapAxiosWithPayment, x402HTTPClient } from "@x402/axios";
    import { ExactEvmScheme } from "@x402/evm/exact/client";
    import { privateKeyToAccount } from "viem/accounts";
    import axios from "axios";
    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 api = wrapAxiosWithPayment(
      axios.create({
        baseURL: process.env.RESOURCE_BASE_URL || "http://127.0.0.1:4021",
      }),
      client
    );

    (async () => {
      const response = await api.get("/weather");
      console.log("Response:", response.data);

      const httpClient = new x402HTTPClient(client);
      const paymentResponse = httpClient.getPaymentSettleResponse((name) =>
        response.headers[name.toLowerCase()]
      );
      console.log("Payment settled:", paymentResponse);
    })();
    ```
  </Tab>
</Tabs>

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](https://docs.x402.org).

## Error handling

```ts theme={null}
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

| name                | type   | required | example                                   | description                     |
| ------------------- | ------ | -------- | ----------------------------------------- | ------------------------------- |
| `EVM_PRIVATE_KEY`   | string | yes      | `"abcd1..."`                              | Wallet key for signing payments |
| `RESOURCE_URL`      | string | yes      | `"https://api.example.com/paid-endpoint"` | Target API URL                  |
| `RESOURCE_BASE_URL` | string | optional | `"http://127.0.0.1:4021"`                 | Base URL when using Axios       |
| USDC                | token  | implied  | USDC on Polygon                           | Payment 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 / case                 | meaning                           | fix                                                                              |
| --------------------------- | --------------------------------- | -------------------------------------------------------------------------------- |
| `MISSING_CONFIG`            | Wallet or URL not set             | Verify `.env` keys                                                               |
| `No scheme registered`      | Client missing scheme for network | Register `ExactEvmScheme` with `"eip155:*"`                                      |
| `Payment already attempted` | Payment failed on retry           | Check wallet balance and facilitator health                                      |
| `402_LOOP`                  | API keeps returning 402           | Ensure seller uses x402 v2 and matching network (`eip155:80002` or `eip155:137`) |

### Do / Don't Do Guardrails

| Do                                                            | Don't                                                                |
| ------------------------------------------------------------- | -------------------------------------------------------------------- |
| Use `@x402/fetch` or `@x402/axios` with v2 packages           | Use legacy `x402-fetch` or `x402-axios` against Polygon facilitators |
| Test on Amoy before mainnet                                   | Hardcode private keys in scripts                                     |
| Read receipts via `x402HTTPClient.getPaymentSettleResponse()` | Parse `PAYMENT-RESPONSE` headers manually                            |
| Use `wrapFetchWithPayment` or `wrapAxiosWithPayment`          | Re-implement 402 logic yourself                                      |

### References

* [@x402/fetch on npm](https://www.npmjs.com/package/@x402/fetch)
* [@x402/axios on npm](https://www.npmjs.com/package/@x402/axios)
* [@x402/evm on npm](https://www.npmjs.com/package/@x402/evm)
* [Official x402 buyer quickstart](https://docs.x402.org/getting-started/quickstart-for-buyers)
* [Using the Polygon Facilitator](./using-polygon-facilitator.mdx)
* [Migration: V1 to V2](./migration-v1-to-v2.mdx)
