Title: x402 pricing & payment
Source: https://nodely.io/docs/x402/payment/

# x402 pricing & payment

Each paid request is paid separately in USDC, using the x402 v2 protocol. You can pay on Algorand mainnet for every API, and on Base or Arc for web search and page scrape. Web search costs 0.0085 USDC on Algorand and 0.009 USDC on Base or Arc; page scrape costs 0.011 USDC on Algorand and 0.012 USDC on Base or Arc. DEX prices (0.001 USDC), account value (0.002 USDC) and NFT image search (0.005 USDC) are paid on Algorand. Nodely pays the network fee on every network, so you only spend USDC.

![The x402 payment flow on Algorand, using the web search API as an example: request, 402 offer, signing, retry, result, and who pays what](https://nodely.io/images/x402/x402-flow.gif)

<a id="prices"></a>

## Prices

| API | Price | Amount (USDC base units) | Pay on |
| --- | --- | --- | --- |
| Web search, `/v1/search` | 0.0085 USDC per query | `8500` | Algorand |
| Web search, `/v1/search` | 0.009 USDC per query | `9000` | Base, Arc |
| Page scrape, `/v1/scrape` | 0.011 USDC per page | `11000` | Algorand |
| Page scrape, `/v1/scrape` | 0.012 USDC per page | `12000` | Base, Arc |
| DEX prices, `/v1/prices/{price,history,pairs,pools,candles}` | 0.001 USDC per call | `1000` | Algorand |
| Account value, `/v1/prices/account` | 0.002 USDC per call | `2000` | Algorand |
| NFT image search, `/v1/images/search`, `/v1/images/similar/{cid}` | 0.005 USDC per call | `5000` | Algorand |

Each route has its own price. Read the current price from the route’s 402 response or from its free pricing route: [`/v1/search/pricing`](https://x402.api.nodely.io/v1/search/pricing), [`/v1/scrape/pricing`](https://x402.api.nodely.io/v1/scrape/pricing), [`/v1/prices/pricing`](https://x402.api.nodely.io/v1/prices/pricing) or [`/v1/images/pricing`](https://x402.api.nodely.io/v1/images/pricing).

<a id="payment-parameters"></a>

## Payment parameters

| Field | Value |
| --- | --- |
| Protocol | x402 v2 |
| Scheme | `exact` |
| Amount | The route’s price in USDC base units (6 decimals), for example `10000` = 0.01 USDC |

Every 402 response and every pricing route also lists the networks, assets and addresses below.

<a id="algorand"></a>

### Algorand

| Field | Value |
| --- | --- |
| Network | `algorand:wGHE2Pwdvd7S12BL5FaOP20EGYesN73k` (Algorand mainnet; the full-genesis-hash form is also accepted) |
| Asset | USDC, ASA `31566704` |
| Receiving address (`payTo`) | `X4O2COYWOFR7XS3EOYEF6MG42Y4Q743SKZMULC776NODRTMMRIVTCOBANQ` |
| Fee payer (`extra.feePayer`) | `X4O2STHZWIA425GOSCKVW3KY6IAW3F6SSV5AZ23HOYFLKCDRTHKWUYNDLY`. It pays the network fee of your payment |
| APIs | All |

<a id="base-and-arc"></a>

### Base and Arc

| Field | Base | Arc |
| --- | --- | --- |
| Network | `eip155:8453` | `eip155:5042` |
| USDC contract (`asset`) | `0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913` | `0x3600000000000000000000000000000000000000` |
| EIP-712 domain (`extra`) | `USD Coin`, version `2` | `USDC`, version `2` |
| APIs | Web search, page scrape | Web search, page scrape |

The receiving address (`payTo`) is the same on both: `0x27BFde54149948b6507eFC3F2B1656e422A2c986`.

<a id="the-payment-flow"></a>

## The payment flow

1.  **Request.** Call a paid route as usual.
2.  **402.** The API answers `402 Payment Required`. The `PAYMENT-REQUIRED` header holds base64-encoded JSON that lists the accepted payments, one per network, and the response body holds the same JSON.
3.  **Sign.** Your client picks the offer for a network where it holds USDC. On Algorand it signs its own USDC transfer (see [Paying on Algorand](https://nodely.io/docs/x402/payment/#paying-on-algorand)); on Base or Arc it signs a USDC transfer authorization (see [Paying on Base or Arc](https://nodely.io/docs/x402/payment/#paying-on-base-or-arc)).
4.  **Retry.** Send the same request again with the signed payment in the `PAYMENT-SIGNATURE` header. The API also accepts the older `X-PAYMENT` header.
5.  **200.** The API returns the result. The `PAYMENT-RESPONSE` header confirms the payment; on Algorand it holds the payment’s transaction id.

Your paying account needs at least **10× the price** in USDC on the network you pay on. On Algorand it also needs its **minimum balance**: about 0.2 ALGO, which covers the account and its USDC opt-in. This ALGO stays in your account; you don’t spend it. On Base and Arc you need USDC only.

<a id="paying-on-algorand"></a>

## Paying on Algorand

<a id="network-fee"></a>

### Network fee

Nodely pays the Algorand network fee. The 402 offer names a fee payer in `extra.feePayer`, and the official client then builds an atomic group of two transactions:

| # | Transaction | Signed by | Fee |
| --- | --- | --- | --- |
| 0 | Payment of 0 ALGO from the fee payer to itself | Nobody yet: the API signs it after checking the group | The whole group’s fee, about 0.002 ALGO |
| 1 | Your USDC transfer to `payTo` for the price | You | 0 |

Both transactions carry the same group id, so neither can go on chain without the other. The API’s signature is only good for this one transfer of yours, and you sign nothing but the USDC you pay. A client that ignores `extra.feePayer` and sends a single USDC transfer with its own fee is also accepted.

Who pays what, per call:

| Who | Pays | To |
| --- | --- | --- |
| You | The price in USDC, for example 0.0085 | Nodely (`payTo`) |
| Nodely (fee payer) | About 0.002 ALGO | The Algorand network |

<a id="what-the-api-checks-before-it-answers"></a>

### What the API checks before it answers

Every check below runs before the API starts the search, scrape or price query. Nothing goes on chain until there is a result.

1.  **The request.** Invalid input is answered `400` and never asks for payment.
2.  **The offer.** The payment header is present and valid x402 v2, and the payment terms you accepted are exactly one of the offers for this route: scheme, network, asset, amount and `payTo`.
3.  **Your transfer.** The transaction is:
    -   a USDC transfer for exactly the price to `payTo`, on Algorand mainnet;
    -   signed with a single key, by you or by the address your account is rekeyed to;
    -   free of close-out, clawback and rekey fields;
    -   valid for long enough that the API can do the work and submit it (the official client’s default window is enough).
4.  **The fee payer’s transaction**, when the fee is sponsored:
    -   a 0-ALGO payment from the fee payer to itself, with no close, rekey or lease;
    -   the same validity window as your transfer;
    -   a fee within a fixed cap;
    -   grouped with your transfer and nothing else.
5.  **Your account**, looked up on chain:
    -   the key that signed is the account’s current signer;
    -   it is opted in to USDC and the holding isn’t frozen;
    -   it holds at least 10× the price, plus any of your payments still settling.
6.  **Replay and limits.** The same payment can’t pay for two results. An account whose payment failed on chain is blocked for 24 hours. Each account may have at most 20 payments settling at once.

When the result is ready, and before any of it is sent, the API submits the payment to Algorand. The response goes out only after the network has accepted the payment. The payment’s transaction id comes back in `PAYMENT-RESPONSE`, and the transaction confirms in the next block, about 3 seconds later.

<a id="paying-on-base-or-arc"></a>

## Paying on Base or Arc

Your client signs an EIP-3009 `transferWithAuthorization` for the USDC contract: a signature that lets exactly the price move from your account to `payTo`, once, before a deadline. You don’t send a transaction yourself. Nodely’s relayer submits your authorization on chain and pays the gas, so on Base you need no ETH. Arc’s gas is paid in USDC, and Nodely pays that too.

Before the API starts the search or scrape, it checks:

1.  **The request and the offer**, as on Algorand: invalid input is answered `400`, and the terms you accepted must be exactly one of the offers for this route.
2.  **Your authorization.** It is signed by your account under the token’s EIP-712 domain, moves exactly the price to `payTo`, hasn’t been used before, and stays valid long enough for the work and the settlement (the official client’s default is enough).
3.  **Your account.** It holds at least 10× the price in USDC, plus any of your payments still settling, and isn’t on USDC’s blocklist.
4.  **Limits.** Each account may have at most 5 payments settling at once. While gas on the network is unusually expensive, new payments get `503`.

The API sends the result first, then submits your authorization. `PAYMENT-RESPONSE` confirms the payment, but its `transaction` field is empty, because the settling transaction is sent right after the response. An account whose authorization then fails on chain, for example because it was cancelled or the USDC was moved first, is blocked for 24 hours.

<a id="client-example-nodejs"></a>

## Client example (Node.js)

The official `@x402/fetch` package handles the 402 and the retry, with `@x402/avm` for Algorand or `@x402/evm` for Base and Arc. Python users can use the `x402` package.

<a id="algorand-client"></a>

### Algorand client

```bash
npm install @x402/core @x402/fetch @x402/avm
```

```js
import { x402Client } from "@x402/core/client";
import { wrapFetchWithPayment } from "@x402/fetch";
import { ALGORAND_MAINNET_CAIP2, ExactAvmScheme, toClientAvmSigner } from "@x402/avm";

// Base64 secret key of an account holding USDC (and its ~0.2 ALGO minimum balance)
const signer = toClientAvmSigner(process.env.ALGORAND_SECRET_KEY_B64);
const client = new x402Client().register(ALGORAND_MAINNET_CAIP2,
  new ExactAvmScheme(signer, { algodUrl: "https://mainnet-api.4160.nodely.dev" }));
const paidFetch = wrapFetchWithPayment(fetch, client);

const res = await paidFetch("https://x402.api.nodely.io/v1/search", {
  method: "POST",
  headers: { "Content-Type": "application/json" },
  body: JSON.stringify({ query: "algorand x402", max_results: 5 }),
});
console.log(await res.json());
```

<a id="base-or-arc-client"></a>

### Base or Arc client

```bash
npm install @x402/core @x402/fetch @x402/evm viem
```

```js
import { x402Client } from "@x402/core/client";
import { wrapFetchWithPayment } from "@x402/fetch";
import { ExactEvmScheme, toClientEvmSigner } from "@x402/evm";
import { privateKeyToAccount } from "viem/accounts";

// Private key (0x…) of an account holding USDC on Base. No ETH needed: Nodely pays the gas.
const signer = toClientEvmSigner(privateKeyToAccount(process.env.EVM_PRIVATE_KEY));
// Base; to pay on Arc, register "eip155:5042" instead
const client = new x402Client().register("eip155:8453", new ExactEvmScheme(signer));
const paidFetch = wrapFetchWithPayment(fetch, client);

const res = await paidFetch("https://x402.api.nodely.io/v1/search", {
  method: "POST",
  headers: { "Content-Type": "application/json" },
  body: JSON.stringify({ query: "base x402", max_results: 5 }),
});
console.log(await res.json());
```

The DEX prices, account value and NFT image search APIs take payment on Algorand only, so use the Algorand client for them.

<a id="what-is-not-charged"></a>

## What is not charged

-   A search where no engine returns any results.
-   A scrape that fails (`502 scrape_failed`) or times out (`504 scrape_timeout`).
-   A scrape where the target page answers with HTTP 4xx or 5xx.
-   A price query that finds no data, for example an asset with no pool or a range with no candle.
-   An account value query for an address never seen on chain (`404`).
-   An image search that names an unknown CID (`404`), sends an unsupported image (`415`), or finds the model or index unavailable (`503`).
-   A request rejected before payment, for example invalid input (`400`).

You can retry a failed attempt with the same signed payment. The number of free retries is limited.

<a id="errors"></a>

## Errors

Error responses are JSON:

```json
{ "error": { "code": "scrape_failed", "message": "…" }, "request_id": "…" }
```

| Status | Meaning |
| --- | --- |
| `400` | Invalid request (bad fields, a disallowed URL). Not charged. |
| `402` | Payment required, or the payment was rejected. The `error` field says why. |
| `429` | Too many requests. |
| `502` | Upstream failure, for example `scrape_failed`. Not charged. |
| `503` | Service temporarily unavailable, or gas on Base or Arc is too expensive right now. |
| `504` | Scrape timed out (`scrape_timeout`). Not charged. |
