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

# Make Payments

> Make x402 payments to access paywalled resources

This guide shows how to make x402 payments from the buyer's perspective. Use the SDK to handle payment flows, interact with paywalled resources, and process 402 Payment Required responses.

## Prerequisites

* Node.js and npm installed
* A SKALE Chain endpoint
* Understanding of x402 protocol
* Familiarity with TypeScript
* A wallet with funds (USDC or supported token)

## Overview

When accessing a paywalled resource, the flow is:

1. Make a request to the protected endpoint
2. Receive a `402 Payment Required` response with payment requirements
3. Create and sign a payment authorization
4. Retry the request with the payment signature header

***

## Environment Setup

Create a `.env` file with the following variables:

```bash theme={null}
# Your wallet private key (never commit this!)
PRIVATE_KEY=0xYourPrivateKey

# USDC token contract on SKALE
PAYMENT_TOKEN_ADDRESS=0x2e08028E3C4c2356572E096d8EF835cD5C6030bD
PAYMENT_TOKEN_NAME="Bridged USDC (SKALE Bridge)"
```

***

## Implementation

<Tabs>
  <Tab title="Coinbase SDK">
    ### Step 1: Install Dependencies

    ```bash theme={null}
    npm install @x402/core @x402/evm viem dotenv
    ```

    ### Step 2: Define Your Chain

    Create a chain configuration for SKALE:

    ```typescript theme={null}
    import { defineChain } from "viem";

    export const skaleChain = defineChain({
        id: 324705682,
        name: "SKALE Base Sepolia",
        nativeCurrency: { decimals: 18, name: "Credits", symbol: "CREDIT" },
        rpcUrls: {
            default: { http: ["https://base-sepolia-testnet.skalenodes.com/v1/base-testnet"] },
        },
    });
    ```

    ### Step 3: Create the Payment Client

    ```typescript theme={null}
    import { x402Client, x402HTTPClient } from "@x402/core/client";
    import { ExactEvmScheme } from "@x402/evm";
    import { privateKeyToAccount } from "viem/accounts";
    import "dotenv/config";

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

    // Create the x402 client with EVM scheme
    const evmScheme = new ExactEvmScheme(account);
    const coreClient = new x402Client().register("eip155:*", evmScheme);
    const httpClient = new x402HTTPClient(coreClient);
    ```

    ### Step 4: Access Paywalled Resources

    ```typescript theme={null}
    async function accessResource(url: string): Promise<unknown> {
        // Make initial request
        const response = await fetch(url, {
            method: "GET",
            headers: { "Content-Type": "application/json" },
        });

        // If no payment required, return data
        if (response.status !== 402) {
            return response.json();
        }

        // Get payment requirements from response
        const responseBody = await response.json();
        const paymentRequired = httpClient.getPaymentRequiredResponse(
            (name: string) => response.headers.get(name),
            responseBody
        );

        // Create payment payload (signs the authorization)
        const paymentPayload = await httpClient.createPaymentPayload(paymentRequired);

        // Get payment headers to send with retry request
        const paymentHeaders = httpClient.encodePaymentSignatureHeader(paymentPayload);

        // Retry request with payment
        const paidResponse = await fetch(url, {
            method: "GET",
            headers: {
                "Content-Type": "application/json",
                ...paymentHeaders,
            },
        });

        if (!paidResponse.ok) {
            throw new Error(`Payment failed: ${paidResponse.status}`);
        }

        return paidResponse.json();
    }
    ```

    ### Complete Working Example

    ```typescript theme={null}
    import { x402Client, x402HTTPClient } from "@x402/core/client";
    import { ExactEvmScheme } from "@x402/evm";
    import { privateKeyToAccount } from "viem/accounts";
    import { createPublicClient, http, formatEther } from "viem";
    import { defineChain } from "viem";
    import "dotenv/config";

    export const skaleChain = defineChain({
        id: 324705682,
        name: "SKALE Base Sepolia",
        nativeCurrency: { decimals: 18, name: "Credits", symbol: "CREDIT" },
        rpcUrls: {
            default: { http: ["https://base-sepolia-testnet.skalenodes.com/v1/base-testnet"] },
        },
    });

    async function main() {
        const privateKey = process.env.PRIVATE_KEY;
        if (!privateKey) {
            throw new Error("PRIVATE_KEY environment variable is required");
        }

        // Setup wallet
        const account = privateKeyToAccount(privateKey as `0x${string}`);
        console.log(`Wallet address: ${account.address}`);

        // Setup x402 client
        const evmScheme = new ExactEvmScheme(account);
        const coreClient = new x402Client().register("eip155:*", evmScheme);
        const httpClient = new x402HTTPClient(coreClient);

        // Access paywalled resource
        const url = "http://localhost:3000/premium/data";

        try {
            const response = await fetch(url, {
                method: "GET",
                headers: { "Content-Type": "application/json" },
            });

            if (response.status === 402) {
                console.log("Payment required, processing...");

                const responseBody = await response.json();
                const paymentRequired = httpClient.getPaymentRequiredResponse(
                    (name: string) => response.headers.get(name),
                    responseBody
                );

                const paymentPayload = await httpClient.createPaymentPayload(paymentRequired);
                const paymentHeaders = httpClient.encodePaymentSignatureHeader(paymentPayload);

                const paidResponse = await fetch(url, {
                    method: "GET",
                    headers: {
                        "Content-Type": "application/json",
                        ...paymentHeaders,
                    },
                });

                const data = await paidResponse.json();
                console.log("Premium data:", data);
            } else {
                const data = await response.json();
                console.log("Data:", data);
            }
        } catch (error) {
            console.error("Error:", error);
        }
    }

    main();
    ```

    ### Run the Client

    ```bash theme={null}
    npx tsx client.ts
    ```
  </Tab>

  <Tab title="Faremeter SDK">
    ### Step 1: Install Dependencies

    ```bash theme={null}
    npm install @faremeter/fetch @faremeter/wallet-evm @faremeter/payment-evm viem dotenv
    ```

    ### Step 2: Define Your Chain

    Create a chain configuration for SKALE:

    ```typescript theme={null}
    import { defineChain } from "viem";

    export const skaleChain = defineChain({
        id: 324705682,
        name: "SKALE Base Sepolia",
        nativeCurrency: { decimals: 18, name: "Credits", symbol: "CREDIT" },
        rpcUrls: {
            default: { http: ["https://base-sepolia-testnet.skalenodes.com/v1/base-testnet"] },
        },
    });
    ```

    ### Step 3: Create the Payment-Enabled Fetch

    The Faremeter SDK wraps the native `fetch` function to automatically handle 402 responses:

    ```typescript theme={null}
    import { createLocalWallet } from "@faremeter/wallet-evm";
    import { createPaymentHandler } from "@faremeter/payment-evm/exact";
    import { wrap as wrapFetch } from "@faremeter/fetch";
    import "dotenv/config";

    const wallet = await createLocalWallet(skaleChain, process.env.PRIVATE_KEY!);

    const fetchWithPayment = wrapFetch(fetch, {
        handlers: [
            createPaymentHandler(wallet, {
                asset: {
                    address: process.env.PAYMENT_TOKEN_ADDRESS as `0x${string}`,
                    contractName: process.env.PAYMENT_TOKEN_NAME || "Bridged USDC (SKALE Bridge)",
                    forwarderName: process.env.PAYMENT_TOKEN_NAME || "Bridged USDC (SKALE Bridge)",
                    forwarderVersion: "1",
                },
            }),
        ],
    });
    ```

    ### Step 4: Access Paywalled Resources

    ```typescript theme={null}
    // The wrapped fetch automatically handles 402 responses
    const response = await fetchWithPayment("http://localhost:3000/premium/data", {
        method: "GET",
        headers: { "Content-Type": "application/json" },
    });

    const data = await response.json();
    console.log("Premium data:", data);
    ```

    ### Complete Working Example

    ```typescript theme={null}
    import { createLocalWallet } from "@faremeter/wallet-evm";
    import { createPaymentHandler } from "@faremeter/payment-evm/exact";
    import { wrap as wrapFetch } from "@faremeter/fetch";
    import { createPublicClient, http, formatEther, defineChain } from "viem";
    import "dotenv/config";

    export const skaleChain = defineChain({
        id: 324705682,
        name: "SKALE Base Sepolia",
        nativeCurrency: { decimals: 18, name: "Credits", symbol: "CREDIT" },
        rpcUrls: {
            default: { http: ["https://base-sepolia-testnet.skalenodes.com/v1/base-testnet"] },
        },
    });

    async function main() {
        const privateKey = process.env.PRIVATE_KEY;
        if (!privateKey) {
            throw new Error("PRIVATE_KEY environment variable is required");
        }

        // Setup wallet
        const wallet = await createLocalWallet(skaleChain, privateKey);
        console.log(`Wallet address: ${wallet.account.address}`);

        // Setup payment-enabled fetch
        const assetAddress = process.env.PAYMENT_TOKEN_ADDRESS as `0x${string}`;
        const assetName = process.env.PAYMENT_TOKEN_NAME || "Bridged USDC (SKALE Bridge)";

        const fetchWithPayment = wrapFetch(fetch, {
            handlers: [
                createPaymentHandler(wallet, {
                    asset: {
                        address: assetAddress,
                        contractName: assetName,
                        forwarderName: assetName,
                        forwarderVersion: "1",
                    },
                }),
            ],
        });

        // Access paywalled resource - payment handled automatically!
        const url = "http://localhost:3000/premium/data";

        try {
            console.log(`Accessing ${url}...`);

            const response = await fetchWithPayment(url, {
                method: "GET",
                headers: { "Content-Type": "application/json" },
            });

            if (!response.ok) {
                throw new Error(`Request failed: ${response.status}`);
            }

            const data = await response.json();
            console.log("Premium data:", data);
        } catch (error) {
            console.error("Error:", error);
        }
    }

    main();
    ```

    ### Run the Client

    ```bash theme={null}
    npx tsx client.ts
    ```

    ### POST Requests with Body

    The wrapped fetch works the same way for POST requests:

    ```typescript theme={null}
    const response = await fetchWithPayment("http://localhost:3000/premium/analyze", {
        method: "POST",
        headers: { "Content-Type": "application/json" },
        body: JSON.stringify({ query: "analyze this data" }),
    });

    const result = await response.json();
    console.log("Analysis result:", result);
    ```
  </Tab>
</Tabs>

***

## Testing Your Client

Make sure you have a server running (see [Accept Payments](/cookbook/x402/accepting-payments)), then run your client:

```bash theme={null}
npx tsx client.ts
```

The client will:

1. Make a request to the protected endpoint
2. Receive the 402 response with payment requirements
3. Sign a payment authorization using your wallet
4. Retry the request with the payment header
5. Receive the premium content

## Best Practices

1. **Use Environment Variables**: Never hardcode private keys
2. **Handle Errors Gracefully**: Always wrap payment logic in try-catch
3. **Check Balances**: Ensure wallet has sufficient funds before making payments
4. **Log Transactions**: Keep track of payments for debugging and accounting

## Security Considerations

* Never expose private keys in client-side code
* Use secure key management (environment variables, secrets manager)
* Validate payment amounts before approving
* Consider implementing spending limits

## Resources

* [Coinbase x402 SDK](https://github.com/coinbase/x402)
* [Faremeter SDK Documentation](https://docs.corbits.dev/api/reference/fetch/overview)
* [x402 Examples Repository](https://github.com/TheGreatAxios/x402-examples)
