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

> ## Agent Instructions
> The Exa API is served at https://api.exa.ai. Authenticate with `Authorization: Bearer $EXA_API_KEY` (or `x-api-key: $EXA_API_KEY`); create keys at https://dashboard.exa.ai/api-keys?utm_source=docs&utm_medium=docs&utm_campaign=markdown_instructions. Every way an agent can get access to Exa is described at https://exa.ai/auth.md.
> Prefer the official SDKs, `exa-py` (`pip install exa-py`) and `exa-js` (`npm install exa-js`); both read `EXA_API_KEY` from the environment.
> Tool-using agents can call Exa without writing code through the hosted MCP server at https://mcp.exa.ai/mcp, or install the Exa agent skill with `npx skills add exa-labs/agent-skills` (skill file: https://exa.ai/docs/skill.md).
> The OpenAPI specs at https://exa.ai/docs/exa-spec.yaml and https://exa.ai/docs/team-management-spec.yaml are the source of truth for request and response schemas.

# Pay with x402

> Use Exa's Search and Contents APIs without an API key. Pay per request with USDC on Arc, Base, World Chain, or Solana via the x402 protocol, including Circle Gateway nanopayments.

## What is x402?

[x402](https://x402.org) is an open payment standard built on the HTTP `402 Payment Required` status code. It lets clients pay for API access per-request using USDC stablecoins, with no accounts, API keys, or subscriptions needed. Exa accepts standard per-request payments on Arc, Base, and Solana, and batched gasless [Circle Gateway nanopayments](#circle-gateway-nanopayments) on Arc, Base, and World Chain.

Exa supports x402 on two endpoints: **`/search`** and **`/contents`**. When you send a request without an API key or payment header, Exa responds with `402` and a `PAYMENT-REQUIRED` header containing pricing details and the supported payment networks. Your client signs a USDC payment, retries the request with a `PAYMENT-SIGNATURE` header, and receives the results once settlement confirms on-chain.

This is ideal for **AI agents** that need to autonomously pay for web search without pre-provisioned credentials.

> [!NOTE]
>
> x402 and API key access are independent. If your request includes an `x-api-key` or `Authorization: Bearer` header, the normal API key billing flow is used and x402 is bypassed entirely.

## Supported endpoints

| Endpoint | Method | Description |
| - | - | - |
| `/search` | POST | Web search with all search types (`instant`, `auto`, `fast`, `deep`, `deep-lite`, `deep-reasoning`) |
| `/contents` | POST | Content retrieval by URL or document ID |

All other endpoints are **not** available via x402.

## How it works

![x402 payment flow sequence diagram: Client sends request to server, gets 402 with PAYMENT-REQUIRED header, creates payment payload, retries with PAYMENT-SIGNATURE, server verifies via facilitator, does work, settles on-chain, returns 200 with results and PAYMENT-RESPONSE](https://mintcdn.com/exa-52/Una64IRjof2yadw_/images/integrations/payments/x402/payment-flow.png?fit=max\&auto=format\&n=Una64IRjof2yadw_\&q=85\&s=5a560d80bb84828e03dfacd61351e9fb)

### Step 1: Discovery

Send a request to a supported endpoint without an API key or payment header:

```bash theme={null}
curl -X POST "https://api.exa.ai/search" \
  -H "Content-Type: application/json" \
  -d '{"query": "best machine learning frameworks", "numResults": 5}'
```

You'll receive a `402` response with a base64-encoded `PAYMENT-REQUIRED` header. Decoded, it looks like:

```json theme={null}
{
  "x402Version": 2,
  "resource": {
    "url": "https://api.exa.ai/search",
    "description": "Exa /search endpoint"
  },
  "accepts": [
    {
      "scheme": "exact",
      "network": "eip155:8453",
      "amount": "7000",
      "asset": "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913",
      "payTo": "0x...",
      "maxTimeoutSeconds": 60,
      "extra": { "name": "USD Coin", "version": "2" }
    },
    {
      "scheme": "exact",
      "network": "solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp",
      "amount": "7000",
      "asset": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v",
      "payTo": "...",
      "maxTimeoutSeconds": 60,
      "extra": { "name": "USD Coin", "version": "2", "feePayer": "..." }
    }
  ]
}
```

The `amount` is in USDC atomic units (6 decimals), so `"7000"` = \$0.007.
The client can pay with any advertised `accepts` entry it supports. Solana entries include facilitator-provided fields such as `extra.feePayer`; use the exact entry from the `PAYMENT-REQUIRED` header when constructing the payment.

### Step 2: Pay and retry

Sign the payment with your wallet and re-send the request with a `PAYMENT-SIGNATURE` header containing your base64-encoded payment payload. The x402 client SDKs handle this automatically.

### Step 3: Settlement

Exa verifies your payment signature with the facilitator, then starts on-chain settlement **in parallel** with processing your request. The response is held until settlement confirms. On success, you receive:

* HTTP `200` with your results
* A `PAYMENT-RESPONSE` header containing the settlement receipt (base64-encoded), including the on-chain transaction hash

If settlement fails, you get `402` with both `PAYMENT-RESPONSE` (error details) and `PAYMENT-REQUIRED` (so you can retry).

## Pricing

x402 uses the same bundled pricing as API key billing. Prices are calculated upfront based on your request parameters (not actual results returned).

### Search (`/search`)

| Search type | Base price (up to 10 results) | Per result beyond 10 |
| - | - | - |
| `lite`, `instant` | \$0.004 / request | N/A (capped at 10) |
| `auto`, `fast` | \$0.007 / request | N/A (capped at 10) |
| `deep-lite` | \$0.012 / request | N/A (capped at 10) |
| `deep` | \$0.012 / request | N/A (capped at 10) |
| `deep-reasoning` | \$0.015 / request | N/A (capped at 10) |

Adding `contents.summary` costs an additional **\$0.001 per result**.

> [!WARNING]
>
> x402 requests are capped at **10 results maximum**. If you request more than 10, `numResults` is silently clamped to 10 and pricing is based on 10 results.

### Contents (`/contents`)

Each content type is charged per page/URL:

| Content type | Price per page |
| - | - |
| `text` | \$0.001 |
| `highlights` | \$0.001 |
| `summary` | \$0.001 |

If you request no content types (no `text`, `highlights`, or `summary`), `text` is enabled by default.

### Examples

| Request | Price | USDC atomic |
| - | - | - |
| `/search` with 10 results, `type: "auto"` | \$0.007 | 7000 |
| `/search` with 5 results, `type: "lite"` | \$0.004 | 4000 |
| `/search` with 3 results + summary, `type: "auto"` | \$0.010 | 10000 |
| `/search` with 10 results, `type: "deep-lite"` | \$0.012 | 12000 |
| `/search` with 10 results, `type: "deep"` | \$0.012 | 12000 |
| `/contents` for 2 URLs with `text: true` | \$0.002 | 2000 |
| `/contents` for 1 URL with `text` + `summary` | \$0.002 | 2000 |

## Quickstart

### Install dependencies

```bash JavaScript theme={null}
npm install @x402/fetch @x402/core @x402/evm viem
# For Solana support, also install:
npm install @x402/svm @solana/kit @scure/base
```

```bash Python theme={null}
pip install "x402[requests,evm]"
# For Solana support, also install:
pip install "x402[svm]" "solana<0.40"

# Or, if using uv:
uv add "x402[requests,evm]"
# For Solana support, also install:
uv add "x402[svm]" "solana<0.40"
```

> [!NOTE]
>
> No install is needed for cURL, but you'll need to handle the 402 challenge and payment signing manually. The SDK approach is recommended for production use.

> [!TIP]
>
> Don't want to manage private keys? [Coinbase Agentic Wallets](https://docs.cdp.coinbase.com/agentic-wallet/welcome) provide TEE-isolated key management for AI agents. Your agent never sees the private key. The wallet is viem-compatible, so it works directly with `@x402/fetch`.

### Make a paid search request

```typescript JavaScript theme={null}
import { wrapFetchWithPayment } from "@x402/fetch";
import { x402Client, x402HTTPClient } from "@x402/core/client";
import { ExactEvmScheme } from "@x402/evm/exact/client";
// For Solana support, also import:
// import { ExactSvmScheme } from "@x402/svm/exact/client";
import { privateKeyToAccount } from "viem/accounts";

const signer = privateKeyToAccount(process.env.WALLET_PRIVATE_KEY as `0x${string}`);
const client = new x402Client();
client.register("eip155:*", new ExactEvmScheme(signer));
// Register a Solana signer too if you want the client to use Solana accept
// entries such as `solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp`:
// client.register("solana:*", new ExactSvmScheme(svmSigner));
const fetchWithPayment = wrapFetchWithPayment(fetch, client);

const response = await fetchWithPayment("https://api.exa.ai/search", {
  method: "POST",
  headers: { "Content-Type": "application/json" },
  body: JSON.stringify({
    query: "best machine learning frameworks",
    numResults: 5,
  }),
});

const data = await response.json();
console.log(data.results);

// Check settlement receipt
const httpClient = new x402HTTPClient(client);
const receipt = httpClient.getPaymentSettleResponse(
  (name) => response.headers.get(name)
);
console.log("Transaction:", receipt?.transaction);
```

```python Python theme={null}
import os
import requests
from eth_account import Account
from x402 import x402ClientSync
from x402.http.clients import wrapRequestsWithPayment
from x402.mechanisms.evm.exact import register_exact_evm_client
from x402.mechanisms.evm.signers import EthAccountSigner

account = Account.from_key(os.environ["WALLET_PRIVATE_KEY"])
client = x402ClientSync()
register_exact_evm_client(
    client,
    EthAccountSigner(account),
    networks="eip155:*",
)
session = wrapRequestsWithPayment(requests.Session(), client)

response = session.post("https://api.exa.ai/search", json={
    "query": "best machine learning frameworks",
    "numResults": 5,
})

data = response.json()
for result in data["results"]:
    print(result["url"], result["title"])
print("Payment response:", response.headers.get("PAYMENT-RESPONSE"))
```

```bash cURL theme={null}
# Step 1: Discovery, get pricing info
curl -s -o /dev/null -w "%{http_code}" -D - \
  -X POST "https://api.exa.ai/search" \
  -H "Content-Type: application/json" \
  -d '{"query": "best machine learning frameworks", "numResults": 5}'
# Returns 402 with PAYMENT-REQUIRED header containing base64-encoded pricing

# Step 2: Sign the payment with your wallet (use the SDK for this)
# Step 3: Retry with payment signature
curl -X POST "https://api.exa.ai/search" \
  -H "Content-Type: application/json" \
  -H "PAYMENT-SIGNATURE: <base64-encoded-payment>" \
  -d '{"query": "best machine learning frameworks", "numResults": 5}'
# Returns 200 with results + PAYMENT-RESPONSE header (settlement receipt)
```

> [!NOTE]
>
> cURL requires manual payment signing. For production, use the JavaScript or Python SDK which handles the full 402 > sign > retry flow automatically.

### Discovery mode (no wallet needed)

Probe pricing without a wallet by sending unauthenticated requests:

```typescript JavaScript theme={null}
const res = await fetch("https://api.exa.ai/search", {
  method: "POST",
  headers: { "Content-Type": "application/json" },
  body: JSON.stringify({ query: "test query", numResults: 3 }),
});

// res.status === 402
const paymentRequired = JSON.parse(
  atob(res.headers.get("PAYMENT-REQUIRED")!)
);
console.log(
  paymentRequired.accepts.map(({ network, amount }) => ({
    network,
    amount,
  }))
);
```

```python Python theme={null}
import base64, json, requests

res = requests.post("https://api.exa.ai/search", json={
    "query": "test query",
    "numResults": 3,
})

# res.status_code == 402
pricing = json.loads(base64.b64decode(res.headers["PAYMENT-REQUIRED"]))
print([(accept["network"], accept["amount"]) for accept in pricing["accepts"]])
```

```bash cURL theme={null}
curl -s -D - -X POST "https://api.exa.ai/search" \
  -H "Content-Type: application/json" \
  -d '{"query": "test query", "numResults": 3}'
# Look for the PAYMENT-REQUIRED header in the 402 response
# Decode it: echo "<header-value>" | base64 -d
```

## Payment networks

Exa advertises every currently supported network in the `accepts` array. Choose the entry that matches your wallet and registered x402 client scheme.

| Network | Identifier | Token | Settlement |
| - | - | - | - |
| Base (Ethereum L2) | `eip155:8453` | USDC | Per-request on-chain transfer |
| Solana mainnet | `solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp` | USDC | Per-request on-chain transfer |
| Arc | `eip155:5042` | USDC | Per-request on-chain transfer |
| Base via Circle Gateway | `eip155:8453` | USDC | Batched nanopayments from your Gateway balance |
| World Chain via Circle Gateway | `eip155:480` | USDC | Batched nanopayments from your Gateway balance |
| Arc via Circle Gateway | `eip155:5042` | USDC | Batched nanopayments from your Gateway balance |

All entries use 6-decimal USDC (`1000000` = \$1.00). The token contract address for each entry is in its `asset` field. Arc and Base each appear twice: once as a standard per-request transfer and once as a [Circle Gateway](https://developers.circle.com/gateway/nanopayments) entry.

> [!TIP]
>
> The Gateway entry is the one with `extra.verifyingContract`. Standard accepts on the same
> network omit that field.

### Circle Gateway nanopayments

[Circle Gateway](https://developers.circle.com/gateway/nanopayments) batches settlement so you do not send an on-chain transfer per request. Deposit USDC into a Gateway Wallet once. Each payment after that is a gasless signature that Circle verifies against your balance.

```typescript theme={null}
import { GatewayClient } from "@circle-fin/x402-batching/client";

const client = new GatewayClient({ chain: "base", privateKey: process.env.PRIVATE_KEY });

// One-time: fund your Gateway balance (on-chain transaction)
await client.deposit("10.00");

// Every request after that is gasless
const { data } = await client.pay("https://api.exa.ai/search", {
  method: "POST",
  body: { query: "latest developments in agentic payments", numResults: 5 },
});
```

Gateway accepts differ from the standard ones in two ways:

* **Signing domain.** Gateway payments are EIP-3009 authorizations signed against the GatewayWallet contract's EIP-712 domain, advertised via `extra.verifyingContract` (plus `extra.name` and `extra.version`), not the USDC token contract. Use Circle's `@circle-fin/x402-batching` client, which reads that metadata. If you build the payment yourself, use the domain from the entry's `extra`.
* **Validity window.** Gateway entries set `maxTimeoutSeconds` to about 7 days (Circle's batch-settlement requirement) instead of 60 seconds. The authorization is still single-use. The facilitator enforces replay protection.

> [!NOTE]
>
> A Gateway-signed payment fails verification if the wallet has no Gateway balance. Use a standard
> entry in that case.

## Rate limits

x402 has its own rate limiting separate from API key limits:

| Limit | Threshold | Window |
| - | - | - |
| Unpaid discovery requests (per IP) | 5 requests | 60 seconds |
| Paid requests (per wallet) | 10 requests/second | 1 second |

After 5 unauthenticated `402` discovery requests from the same IP within 60 seconds, further requests return `429 Too Many Requests`. Making a successful paid request decrements the counter.

Per-wallet QPS is enforced across all paid requests from the same wallet address.

## Headers reference

### Request headers

| Header | Description |
| - | - |
| `PAYMENT-SIGNATURE` | Base64-encoded payment payload (x402 v2) |
| `payment-signature` | Alias (also accepted) |
| `x-payment` | Legacy alias (v1 compatibility) |

### Response headers

| Header | When | Description |
| - | - | - |
| `PAYMENT-REQUIRED` | `402` responses | Base64-encoded `PaymentRequired` object with pricing and payment instructions |
| `PAYMENT-RESPONSE` | `200` or `402` (after payment attempt) | Base64-encoded settlement result with transaction hash or error |

## Error codes

| Status | Tag | Description |
| - | - | - |
| `402` | `X402_PAYMENT_REQUIRED` | No payment provided. Includes pricing in `PAYMENT-REQUIRED` header |
| `402` | `X402_VERIFICATION_FAILED` | Payment signature did not pass facilitator verification |
| `400` | `X402_INVALID_SIGNATURE` | Malformed or unparseable payment signature |
| `429` | `X402_TOO_MANY_UNPAID` | Too many unpaid discovery requests from this IP |
| `429` | `X402_WALLET_RATE_LIMITED` | Wallet exceeded 10 requests/second |
| `500` | `X402_INTERNAL_ERROR` | Server-side error generating payment requirements |

## FAQ

> [accordion] Can I use x402 and an API key together?
>
> If your request includes an `x-api-key` header or `Authorization: Bearer` token, the API key flow takes priority and x402 is bypassed. They don't stack. It's one or the other per request.

> [accordion] What happens if settlement fails after my request was processed?
>
> Your response is blocked. You receive a `402` with both `PAYMENT-RESPONSE` (containing the error) and `PAYMENT-REQUIRED` (so your client can retry). No results are returned until settlement succeeds.

> [accordion] Why is numResults capped at 10?
>
> x402 requests enforce a maximum of 10 results per search. If you need more, use the API key flow.

> [accordion] Should I use a standard entry or the Circle Gateway entry?
>
> Use a standard entry for occasional requests from a funded USDC wallet: no setup, one on-chain
> settlement per request. Use Circle Gateway when you make many requests (agents, pipelines):
> deposit once, then every payment is a gasless signature from your Gateway balance. Both charge
> the same Exa price.

> [accordion] Which wallets are supported?
>
> Any EVM-compatible wallet that can sign EIP-712 typed data on Arc, Base, or World Chain, or a Solana wallet supported by the x402 SVM client for `solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp`. The x402 SDK supports `viem`, `ethers`, Coinbase Wallet signers, and Solana SVM signers. Gateway payments use Circle's `@circle-fin/x402-batching` client. For EVM-based AI agents, [Coinbase Agentic Wallets](https://docs.cdp.coinbase.com/agentic-wallet/welcome) offer TEE-isolated key management so your agent never handles raw private keys directly.

## Resources

* [x402 protocol docs](https://docs.x402.org): full protocol specification
* [x402 GitHub](https://github.com/coinbase/x402): open-source SDKs and examples
* [@x402/fetch on npm](https://www.npmjs.com/package/@x402/fetch): fetch wrapper for automatic payment handling
* [@x402/svm on npm](https://www.npmjs.com/package/@x402/svm): Solana/SVM exact payment support
* [Circle Gateway nanopayments](https://developers.circle.com/gateway/nanopayments): batched gasless payments from a Gateway balance
* [@circle-fin/x402-batching on npm](https://www.npmjs.com/package/@circle-fin/x402-batching): buyer client for the Circle Gateway entries
* [Exa Search API guide](https://exa.ai/docs/search/quickstart.md): full search parameter reference
* [Exa Contents API guide](https://exa.ai/docs/contents/quickstart.md): full contents parameter reference
