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

# x402 Payments

> Call the Webacy API without an API key by paying per request in USDC on Base using the x402 protocol, with prepaid credit tokens for follow-up requests.

x402 lets you call the Webacy API without an API key by paying per request in USDC on [Base](https://base.org/). Instead of signing up for a key, you make a request, receive a payment challenge, pay on-chain, and retry. It works on any endpoint that supports it — supported endpoints are marked in the [API Reference](/api-reference/introduction) with a `402` response. Think of it as an alternative access model alongside API keys, ideal for agents and integrations that need to pay as they go.

## Prerequisites

Before you begin, ensure you have:

* A Base-compatible wallet funded with USDC to cover the payment
* The ability to sign an on-chain payment (directly or through an x402 client library)

## How It Works

<Steps>
  <Step title="Call a supported endpoint without an API key">
    Send your request as usual, but omit the `x-api-key` header.
  </Step>

  <Step title="Receive a 402 Payment Required">
    The response includes a `payment-required` header — base64-encoded JSON payment requirements. Decode it and read the first entry of the `accepts` array for the amount (`accepts[0].amount`), the USDC contract (`accepts[0].asset`), and the pay-to address (`accepts[0].payTo`).
  </Step>

  <Step title="Pay on-chain">
    Send `accepts[0].amount` of USDC on Base to `accepts[0].payTo`. Amounts are in USDC base units (6 decimals), so `500000` is 0.50 USDC.
  </Step>

  <Step title="Retry the same request with your payment proof">
    Resend the identical request, this time with a `payment-signature` header containing your signed payment proof.
  </Step>

  <Step title="Get your response">
    You receive the endpoint's normal response, plus `x-credit-token` and `x-credit-balance-cu` headers.
  </Step>
</Steps>

## Credit Tokens

After you pay, Webacy returns a **credit token** in the `x-credit-token` header. This token holds the prepaid balance left over from your payment.

Keep it. On subsequent requests, send it back as an `x-credit-token` header to spend your prepaid balance instead of paying again. The `x-credit-balance-cu` header in each response tells you how much balance remains. When it runs out, the next request returns another `402` and you pay again.

<Note>
  Store your credit token securely and reuse it across requests. It represents prepaid balance — treat it like a bearer token.
</Note>

## Headers

| Header | Direction | Purpose |
| - | - | - |
| `payment-signature` | Request | Signed payment proof |
| `payment-required` | Response (402) | Base64-encoded JSON payment requirements (an `accepts` array with amount, asset, and `payTo`) |
| `x-credit-token` | Request and response | Bearer token for your prepaid balance |
| `x-credit-balance-cu` | Response | Prepaid balance remaining after the call |

## Pricing

You pay the same per-endpoint price as with an API key, so an endpoint costs you the same either way. The `402` challenge gives you the exact amount for the request you are making.

There is a **\$0.50 minimum** per payment. If your payment covers more than a single request needs, the surplus becomes extra prepaid balance on your credit token, which you can spend on later requests.

## Supported Chains

Today, x402 payments are supported on **Base** using USDC. Support for additional chains is coming.

## Example

The following walks through the full challenge-pay-retry loop against the address risk endpoint.

<CodeGroup>
  ```bash cURL theme={null}
  # (a) Initial request with no API key -> 402 with the payment-required header
  curl -i -X GET "https://api.webacy.com/addresses/0x742d35Cc6634C0532925a3b844Bc454e4438f44e?chain=eth"

  # (b) The 402 response carries a base64 payment-required header. Decoded, it looks like:
  # {
  #   "x402Version": 2,
  #   "error": "Payment required",
  #   "resource": { "url": "https://api.webacy.com/addresses/0x742d...e?chain=eth" },
  #   "accepts": [
  #     {
  #       "scheme": "exact",
  #       "network": "eip155:8453",                                  # Base mainnet
  #       "amount": "500000",                                        # 0.50 USDC (6 decimals)
  #       "asset": "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913",     # USDC on Base
  #       "payTo": "0x6f9F5cf7D85B82BB0d519AeF9341241C2fDc83fc",
  #       "maxTimeoutSeconds": 300
  #     }
  #   ]
  # }

  # ...pay accepts[0].amount of USDC on Base to accepts[0].payTo...

  # (c) Retry the same request with your signed payment proof
  curl -i -X GET "https://api.webacy.com/addresses/0x742d35Cc6634C0532925a3b844Bc454e4438f44e?chain=eth" \
    -H "payment-signature: YOUR_SIGNED_PAYMENT"

  # Response now returns the data plus:
  #   x-credit-token: <token>
  #   x-credit-balance-cu: <remaining balance>
  ```

  ```javascript JavaScript theme={null}
  // Illustrative flow. The pay() step is a placeholder for signing the payment
  // with your Base wallet or an x402 client library (see the note below).
  const url =
    'https://api.webacy.com/addresses/0x742d35Cc6634C0532925a3b844Bc454e4438f44e?chain=eth';

  // (a) Initial request with no API key -> 402 with the payment-required header
  let res = await fetch(url);

  if (res.status === 402) {
    // (b) Decode the base64 payment requirements
    const challenge = JSON.parse(atob(res.headers.get('payment-required')));
    const { payTo, amount, asset, network } = challenge.accepts[0];

    // ...pay `amount` of USDC (`asset`) on `network` to `payTo`,
    //    then produce a signed payment proof...
    const paymentSignature = await pay(challenge);

    // (c) Retry the same request with your signed payment proof
    res = await fetch(url, {
      headers: { 'payment-signature': paymentSignature },
    });
  }

  const data = await res.json();
  console.log(res.headers.get('x-credit-token'));      // save this for later requests
  console.log(res.headers.get('x-credit-balance-cu')); // remaining balance
  ```
</CodeGroup>

<Note>
  Producing the `payment-signature` means signing the payment with your Base wallet. x402 client libraries can automate the full challenge-pay-retry loop for you.
</Note>

For the complete `402` response schema on any endpoint that supports x402, see the [API Reference](/api-reference/introduction).


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.