# NERO 402 — Full documentation

> NERO 402 is the first AA-native x402 settlement scheme: ERC-4337 smart-contract wallets pay any API over HTTP 402 with paymaster-sponsored gas, holding no native token.

This file bundles the complete NERO 402 documentation for single-request ingestion. Source: https://docs.x402.nerochain.io. API spec: https://docs.x402.nerochain.io/openapi.json.

## Contents

- [FAQ](https://docs.x402.nerochain.io/docs/faq)
- [Welcome to NERO 402](https://docs.x402.nerochain.io/docs)
- [Middleware hooks](https://docs.x402.nerochain.io/docs/advanced/middleware-hooks)
- [Session keys and spending caps](https://docs.x402.nerochain.io/docs/advanced/session-keys)
- [The aa-native scheme](https://docs.x402.nerochain.io/docs/core-concepts/aa-native-scheme)
- [Client and server](https://docs.x402.nerochain.io/docs/core-concepts/client-server)
- [Facilitator](https://docs.x402.nerochain.io/docs/core-concepts/facilitator)
- [HTTP 402](https://docs.x402.nerochain.io/docs/core-concepts/http-402)
- [Networks and tokens](https://docs.x402.nerochain.io/docs/core-concepts/networks)
- [Paymaster](https://docs.x402.nerochain.io/docs/core-concepts/paymaster)
- [Settlement contract](https://docs.x402.nerochain.io/docs/core-concepts/settlement-contract)
- [Wallet](https://docs.x402.nerochain.io/docs/core-concepts/wallet)
- [Quickstart for agents](https://docs.x402.nerochain.io/docs/getting-started/agents)
- [Installation](https://docs.x402.nerochain.io/docs/getting-started/installation)
- [Quickstart for merchants](https://docs.x402.nerochain.io/docs/getting-started/merchants)
- [Delegated agent pattern](https://docs.x402.nerochain.io/docs/guides/delegated-agent)
- [MCP server with x402](https://docs.x402.nerochain.io/docs/guides/mcp-server)
- [Upstream interoperability](https://docs.x402.nerochain.io/docs/guides/upstream-interop)
- [Web3Auth integration](https://docs.x402.nerochain.io/docs/guides/web3auth-integration)
- [SettlementContract reference](https://docs.x402.nerochain.io/docs/reference/contract)
- [Error codes](https://docs.x402.nerochain.io/docs/reference/errors)
- [Whitepaper](https://docs.x402.nerochain.io/docs/reference/whitepaper)
- [Wire format](https://docs.x402.nerochain.io/docs/reference/wire-format)
- [SDK overview](https://docs.x402.nerochain.io/docs/sdk/overview)
- [@nerochain/x402-aa](https://docs.x402.nerochain.io/docs/sdk/x402-aa)
- [@nerochain/x402-client](https://docs.x402.nerochain.io/docs/sdk/x402-client)
- [@nerochain/x402-extensions](https://docs.x402.nerochain.io/docs/sdk/x402-extensions)
- [@nerochain/x402-server](https://docs.x402.nerochain.io/docs/sdk/x402-server)
- [@nerochain/x402-types](https://docs.x402.nerochain.io/docs/sdk/x402-types)

## Facilitator API

Base URL: `https://facilitator.x402.nerochain.io` — OpenAPI: [https://docs.x402.nerochain.io/openapi.json](https://docs.x402.nerochain.io/openapi.json)

- `GET /supported` — schemes, networks, and allowlisted assets the facilitator accepts.
- `POST /verify` — validate a signed payment payload without settling.
- `POST /settle` — verify then settle on chain; returns the transaction hash. Idempotent per request.
- `GET /health` — service status.

Merchant servers call `/verify` and `/settle`; agents never call the facilitator directly.

## Networks

- **NERO Chain mainnet** — `eip155:1689` (chainId 1689). SettlementContract `0x5eCfc64f2339992668f555918674B604F97B412D`. Assets: USDT, USDC.e, USDC.arb.
- **NERO Chain testnet** — `eip155:689` (chainId 689). SettlementContract `0x925dbba44570683ac8da99be08bc5ece8cf5a8c6`. Asset: DEMO-USDT (public mint, self-faucet). Faucet: https://app.testnet.nerochain.io/faucet.

---

# FAQ

> Common questions about NERO 402, the aa-native scheme, and the reference implementation.

## What is NERO 402?

A reference implementation of an additional x402 settlement scheme called `aa-native`. Where the upstream `exact` scheme requires the paying account to be an EOA capable of signing EIP-3009, `aa-native` lets ERC-4337 smart contract wallets pay merchants directly. A paymaster sponsors the gas, so the agent's SCW does not need to hold the chain's native asset.

## How does NERO 402 differ from upstream x402?

The wire envelope is the same; only the inner `payload` differs per scheme. NERO 402 ships its own facilitator that supports both `exact` and `aa-native`, plus an SDK that produces and consumes both. Anywhere the `exact` scheme is involved, NERO 402's facilitator interoperates with unmodified upstream `@x402/fetch` clients.

## Do I need a NERO Chain native balance?

For `aa-native`: no. The paymaster sponsors UserOp gas, including the SCW's own first-time deployment. The agent only ever holds the settlement asset (USDT, USDC, or DEMO-USDT on testnet).

For `exact`: yes. The paying EOA must hold native gas. (Strictly speaking, the facilitator's submitter EOA is what pays; but if the agent ever needs to do anything else on chain, it needs gas.)

## Is the settlement contract audited?

Not as of this version. The v1.0 release of the SDK packages is conditional on a clean external audit. Mainnet deployments to date have processed sub-dollar quantities of USDT in narrowly scoped tests; do not route significant production traffic through the pre-audit contract.

## Can I run a self-hosted facilitator?

Yes. The reference facilitator is at [`apps/facilitator/`](https://github.com/nerochain/nero-x402/tree/main/apps/facilitator). It runs on Node 20+, uses Hono, and is small enough to deploy on Vercel Functions, Fly.io, Railway, or any Node host. A self-hosted facilitator handles its own paymaster relationship and bears the gas cost for `aa-native` settlements it submits.

## Can my agent pay a merchant on a different x402 facilitator?

If the merchant uses `exact`, yes — `@nerochain/x402-client` is wire-compatible with the upstream V2 spec. If the merchant requires `aa-native`, the merchant's facilitator must support `aa-native`. Currently only the NERO 402 facilitator does; this will broaden as the spec graduates upstream.

## What chains are supported?

NERO mainnet (`eip155:1689`) and NERO testnet (`eip155:689`). Adding a chain requires a fresh `SettlementContract` deployment on that chain plus extending the facilitator's configuration. The scheme itself is chain-agnostic.

## What tokens can a merchant accept?

Whatever is on the settlement contract's allowlist. On mainnet that's USDT and USDC. On testnet it's DEMO-USDT (a public-mint clone for self-faucet). Adding a token is an owner action on the contract.

## How do I get a paymaster API key?

From the [NERO AA Platform dashboard](https://docs.nerochain.io/en/developer-tools/aa-platform). The same key works against both testnet and mainnet projects.

## What happens if a UserOp fails on chain?

The facilitator's `/settle` returns `errorCode: "user_op_failed"` with the surfaced revert reason. The `requestHash` is released from the in-flight registry, so the agent can retry (typically with a new `clientNonce`, since the failure may have been timing-sensitive).

## What if the same `requestHash` is settled twice?

The on-chain settlement contract reverts the second call with `AlreadySettled(bytes32)`. The off-chain replay registry rejects it earlier with `errorCode: "replay"` to save the bundler round-trip. Only the on-chain check is authoritative.

## How do I refund a payment?

You don't, in v1. The settlement contract has no refund function. A successful settlement is final. Refund logic, if you need it, lives at the application layer — for example, a merchant SDK that holds funds and only forwards them after the response is delivered successfully.

## Can I pay multiple merchants in one HTTP request?

No. One HTTP request, one payment. To pay multiple merchants, make multiple HTTP requests. The reference SDK does not batch across merchants because each merchant's `requestHash` is independent.

## Why ERC-4337 v0.6 and not v0.7?

NERO Chain's bundler currently runs v0.6. The SDK targets v0.6's `UserOperation` shape (`paymasterAndData` is a single `bytes`, not the split form introduced in v0.7). When the chain upgrades, the SDK will follow.

## Is NERO 402 a new payment standard?

It's an extension to x402 V2. The wire envelope is unchanged; only the `aa-native` scheme name and inner payload are new. The path to upstream standardization runs through `coinbase/x402#639`.

## Where do I report bugs or feature requests?

The repo is at [github.com/nerochain/nero-x402](https://github.com/nerochain/nero-x402). Issues and PRs are open.


---

# Welcome to NERO 402

> An AA-native settlement scheme for x402, with a reference implementation on NERO Chain.

NERO 402 is the first production implementation of an AA-native settlement scheme for the [x402 V2](https://www.x402.org/writing/x402-v2-launch) HTTP payment protocol. Where the upstream `exact` scheme requires the paying account to be an EOA capable of signing EIP-3009 typed data, the `aa-native` scheme defined here lets ERC-4337 smart contract wallets pay merchants directly. A paymaster sponsors the gas, so the agent never needs to hold the chain's native asset.

This site is the developer reference for everything in the stack:

- The four `@nerochain/x402-*` packages.
- The deployed `SettlementContract` on NERO mainnet and testnet.
- The reference facilitator service that speaks both `exact` and `aa-native`.
- The whitepaper that specifies the scheme.

## Pick your path

If you are an **agent author** wanting to call paid APIs, start with [Quickstart for agents](/docs/getting-started/agents).

If you are a **merchant** wanting to gate an endpoint behind payment, start with [Quickstart for merchants](/docs/getting-started/merchants).

If you want the **protocol details**, read the [whitepaper](/whitepaper.pdf) or the [aa-native scheme](/docs/core-concepts/aa-native-scheme) page.

## What's distinctive about NERO 402

- **Smart contract wallet payments.** The paying account is an ERC-4337 SCW. EOAs are still supported via the `exact` scheme.
- **Gas-sponsored from day one.** Type-0 paymaster sponsorship means the agent's SCW spends zero NERO native on every paid call, including its own first-time deployment.
- **Stable wire format.** The envelope is the canonical x402 V2 payload (`@x402/core@2.11.0`); only the inner `payload` differs per scheme. Unmodified upstream `exact` clients interoperate with the reference facilitator out of the box.
- **One on-chain settlement contract.** Replay-protected, owner-allowlisted tokens, UUPS-upgradeable. Merchants are arguments to `settle()`, not separate deployments.

## What's not done yet

The settlement contract has not been audited; v1.0 publication of the SDK packages waits on that. Mainnet deployments to date have processed sub-dollar quantities of USDT under controlled conditions. The whitepaper is published as a draft for community review prior to upstream submission.


---

# Middleware hooks

> Customize the merchant middleware's behavior at well-defined extension points.

`@nerochain/x402-server` exposes its core as two callable functions, `gateRequest` and `settleAfterHandler`. The four framework adapters (Express, Hono, Fastify, Next) are thin wrappers around these. If you need behavior the adapters do not provide directly, drop down to the core and assemble your own pipeline.

## When to use the core directly

Common reasons:

- You want to log every verified payload before invoking the handler (custom audit trail, analytics).
- You want to skip settlement on cache hits (return `304 Not Modified` without paying).
- You want to invoke the handler twice — once for verification's `payer` to scope the response, once after settlement.
- You're writing a new framework adapter for a stack the SDK does not ship support for.

## The core API

```ts
import { gateRequest, settleAfterHandler } from "@nerochain/x402-server";

// Stage 1: gate
const gate = await gateRequest(
  { method: req.method, url: req.url, headers: req.headers },
  options,
);

if (gate.kind === "challenge")
  return respondWith(402, gate.body, gate.headers);
if (gate.kind === "verify_failed")
  return respondWith(402, gate.body, gate.headers);
if (gate.kind === "facilitator_error")
  return respondWith(502, gate.body, gate.headers);

// gate.kind === "proceed"
// gate carries: paymentPayload, paymentRequirements, verifyResult.payer

// Run merchant handler
const handlerResponse = await runHandler(req, gate.verifyResult.payer);

// Stage 2: settle (if handler succeeded)
if (handlerResponse.status >= 200 && handlerResponse.status < 300) {
  const settle = await settleAfterHandler(
    {
      paymentPayload: gate.paymentPayload,
      paymentRequirements: gate.paymentRequirements,
      verifyResult: gate.verifyResult,
    },
    options,
  );

  if (settle.kind === "ok") {
    handlerResponse.headers.set(
      "PAYMENT-RESPONSE",
      settle.paymentResponseHeader,
    );
  } else {
    return respondWith(502, settle.body, settle.headers);
  }
}

return handlerResponse;
```

The returned objects carry their own `status`, `headers`, and `body`. The adapter's job is to translate them into the framework's response API.

## Lifecycle hooks via wrapping

The SDK doesn't expose explicit pre/post hooks; instead, customize by wrapping the handler:

```ts
const customHandler = async (req: Request) => {
  const start = Date.now();
  const res = await innerHandler(req);
  await metrics.observe({
    duration: Date.now() - start,
    status: res.status,
    payer: req.x402Payer,
  });
  return res;
};
```

For pre-handler hooks, run code between `gate` returning `proceed` and calling the handler. For post-settle hooks, run code between `settleAfterHandler` returning `ok` and returning the response.

## Skipping settlement

If your handler decides the response is a cache hit and the agent should not be charged:

```ts
const handlerResponse = await runHandler(...);
if (handlerResponse.status === 304) {
  // Return without calling settleAfterHandler.
  // The response has no PAYMENT-RESPONSE header.
  return handlerResponse;
}
// Otherwise, settle as usual.
```

The agent will receive a 304 with no settlement receipt. This is wire-format compliant; the agent's `readSettlementReceipt(res)` returns `null` and the caller can handle it as "no payment was needed".

## Settling before the handler runs

Set `settleBeforeHandler: true` in the middleware options. The default is `false` (handler first, settle after); the alternative settles up front and lets the handler run knowing the payment is final.

This is the right default for handlers with side effects you don't want to roll back if settlement fails (sending email, writing to external systems). The trade-off is that a handler that throws after settlement leaves the agent paying for nothing.


---

# Session keys and spending caps

> How to delegate scoped spending power to an agent without giving up the SCW's owner key.

In the canonical `aa-native` flow the SCW's owner key signs every UserOp. For an agent that needs to spend autonomously, this means either keeping the owner key online indefinitely (full delegation) or using a different account contract that supports scoped delegation.

ERC-4337 supports session keys at the account-contract layer. The `aa-native` wire format is unaffected by which account contract you use; only the on-chain validation logic changes.

## What a session key buys you

A session key is a separate keypair the SCW's owner authorizes for a constrained subset of operations. Constraints are enforced by the account contract during `validateUserOp`. Typical constraints:

- **Time-bounded.** "Valid until `expiry` timestamp."
- **Method-bounded.** "May only call `SettlementContract.settle(...)`."
- **Amount-bounded.** "May spend at most 10 USDT/day."
- **Counterparty-bounded.** "May only target merchants in this allowlist."

When the constraints are exceeded, the account contract rejects validation and the bundler refuses to submit the UserOp. The owner can revoke a session key at any time by sending a single transaction.

## Why this is not in the canonical SDK

The canonical `SimpleAccount` contract (the factory the reference SDK targets at `0x9406Cc6185a346906296840746125a0E44976454`) does not implement session-key validation. Adding it requires deploying a different account contract.

Several account contracts in the ERC-4337 ecosystem do support session keys:

- **Kernel** (ZeroDev) — validator plugins, including session-key validators with policies.
- **Safe with `Safe4337Module`** — Safe accounts as ERC-4337 wallets, with module-based delegation.
- **Biconomy Smart Account** — pluggable validation modules, session-key module included.

Each comes with its own factory and account-contract address. The wire-format implications for `aa-native` are zero: the verifier ABI-decodes `userOp.callData` to a `SettlementContract.settle(...)` call regardless of which account contract is the `userOp.sender`.

## Plugging an alternative account contract into the SDK

`@nerochain/x402-aa`'s `aaNativeSigner` accepts `entryPoint` and `accountFactory` options. Override them to use a different account contract:

```ts
const signer = aaNativeSigner({
  signer: ownerOrSessionKeyWallet,
  rpcUrl, bundlerUrl, paymasterUrl, paymasterApiKey,
  settlementContract,
  entryPoint:     "0x...",   // EntryPoint v0.6 for the chain
  accountFactory: "0x...",   // Kernel / Safe / Biconomy factory
});
```

The SDK builds the UserOp via the `userop` SDK, which respects whatever factory you point it at. For account contracts that need additional middleware (signature shape changes, validator selection, etc.), you'll likely want to drop down from `aaNativeSigner` to a custom `PaymentSigner` implementation that knows about your account contract's specifics.

## A future @nerochain/x402-aa-session

A planned package, `@nerochain/x402-aa-session`, will package up the session-key flow for one or more popular account contracts as a configuration option. Expected surface:

```ts
const signer = aaNativeSessionSigner({
  ownerSigner,                   // the SCW's owner — used to sign session-key authorizations
  sessionKey: { ... },           // generated or imported session key
  scopes: {
    spendCap: parseUnits("10", 6),    // 10 USDT/day
    targets: [SETTLEMENT_CONTRACT],
    expiry: Date.now() + 24 * 3600 * 1000,
  },
  rpcUrl, bundlerUrl, paymasterUrl, paymasterApiKey,
  settlementContract,
});
```

This is a future deliverable, not something shipped today. The ephemeral SCW pattern (see [Delegated agent](/docs/guides/delegated-agent)) covers most demo and trusted-environment use cases without it.

## When you actually need session keys

- Multi-user platforms where the operator runs LLM agents on behalf of users and cannot hold each user's owner key online.
- Long-running autonomous agents that should keep operating across user-session boundaries.
- Cost-capped agent budgets where a runaway prompt cannot drain the wallet.

For one-off scripts or single-user demos, the ephemeral-SCW pattern is enough.


---

# The aa-native scheme

> x402 settlement scheme designed for ERC-4337 smart contract wallets, where the payment payload carries a signed UserOperation.

`aa-native` is the settlement scheme that lets ERC-4337 smart contract wallets participate in x402 payments. It is the scheme NERO 402 was built to ship; its formal definition is in the [whitepaper](/whitepaper.pdf).

This page summarizes what changes from the upstream `exact` scheme and points at the more detailed concept pages for each piece.

## The shape change

In `exact`:

- The agent (an EOA) signs an EIP-3009 `transferWithAuthorization` typed authorization.
- The facilitator submits the authorization directly to the token contract.
- The token contract recovers the signer via `ecrecover` and moves the funds.

In `aa-native`:

- The agent (an ERC-4337 SCW) signs a `UserOperation` whose `callData` invokes a settlement contract.
- The facilitator submits the UserOp through a bundler.
- The settlement contract is the `msg.sender` of the token transfer, which means any standard ERC-20 works.

The wire envelope is unchanged. Only the inner `payload` differs:

```json
{
  "x402Version": 2,
  "accepted": {
    "scheme": "aa-native",
    "network": "eip155:1689",
    "amount": "1000",
    "asset": "0x...",
    "payTo": "0x...",
    "maxTimeoutSeconds": 60
  },
  "payload": {
    "userOp": { "sender": "0x...", "callData": "0x...", ... },
    "settlementCallSpec": {
      "merchant":   "0x...",
      "token":      "0x...",
      "amount":     "1000",
      "requestHash":"0x..."
    }
  },
  "extensions": null
}
```

The facilitator decodes `userOp.callData` and asserts it resolves to a `SettlementContract.settle(merchant, token, amount, requestHash)` invocation matching `settlementCallSpec`. This prevents an agent from signing a UserOp that does something different from what it claims.

## Why a separate scheme

Both schemes occupy distinct positions in the design space. The full comparison is in the whitepaper §3; the short version:

| | `exact` | `aa-native` |
|---|---|---|
| Account type | EOA | ERC-4337 SCW |
| Required token feature | EIP-3009 | standard ERC-20 |
| Agent native-asset balance | required | not required (paymaster sponsors) |
| Settlement caller | facilitator EOA | bundler → SCW |

Most widely deployed ERC-20 contracts, including USDT on most chains, do not implement EIP-3009. `aa-native` works against any standard ERC-20 because the settlement contract calls `transferFrom` from the SCW's already-authorized state.

## Coexistence with `exact`

The two schemes coexist on the same facilitator. A merchant accepting both signals support in `paymentRequirements[]` and lets the client pick. The reference NERO 402 facilitator implements both for interoperability with unmodified upstream `@x402/fetch` clients (see the [upstream interop guide](/docs/guides/upstream-interop)).

## Where to read more

- [HTTP 402](/docs/core-concepts/http-402) — the wire format the scheme rides on.
- [Wallet](/docs/core-concepts/wallet) — how the SCW signs the UserOp.
- [Paymaster](/docs/core-concepts/paymaster) — how gas gets sponsored.
- [Settlement contract](/docs/core-concepts/settlement-contract) — what the UserOp calls.
- [Facilitator](/docs/core-concepts/facilitator) — what verifies and submits.
- [Whitepaper §2](/whitepaper.pdf) — the normative specification.


---

# Client and server

> The roles and responsibilities of the agent (client) and the merchant (server) in x402.

x402 has two principal participants:

- **The client (agent)** — the party trying to access a paid resource. May be a Node script, an LLM agent, a browser tab, or any HTTP client.
- **The server (merchant)** — the party hosting the paid resource. An Express, Hono, Fastify, or Next.js app, typically.

A third party — the **facilitator** — exists to keep the merchant out of chain-specific code. Its role has its own [page](/docs/core-concepts/facilitator).

## Client responsibilities

The client owns:

- The signing key for its account. For the `exact` scheme this is an EOA; for `aa-native` it is the EOA that owns an ERC-4337 SCW.
- The choice of which `accepts` entry to satisfy when the merchant offers multiple.
- The HTTP retry on 402.
- Decoding the `PAYMENT-RESPONSE` header to obtain the on-chain receipt.

The reference implementation handles all of this through `x402Fetch({signer})`. The agent's code is a single fetch call:

```ts
const f = x402Fetch({ signer: aaNativeSigner({...}) });
await f("https://merchant/api/resource", { method: "POST", body });
```

## Server responsibilities

The server owns:

- The price and asset list. Encoded in `PaymentRequirements` and emitted on every 402 response.
- The decision of when to invoke the protected handler (after `/verify` succeeds, typically) and when to settle (after the handler returns 2xx, typically).
- Forwarding `/verify` and `/settle` calls to the facilitator.
- Attaching the `PAYMENT-RESPONSE` header on the final 200.

The reference middleware (`@nerochain/x402-server`) handles the wire format and the facilitator round-trips automatically. The server author writes a normal handler:

```ts
app.use("/api/llm", x402Express({...}), (req, res) => {
  res.json({ ok: true, payer: req.x402Payer });
});
```

`req.x402Payer` is populated by the middleware after a successful `/verify`. It is the SCW (or EOA, for `exact`) that paid for this request.

## What the client never knows

- The merchant's facilitator URL.
- Whether the merchant verifies before or after running the handler.
- The merchant's HMAC secret for talking to the facilitator.
- The on-chain submission path (bundler, paymaster). The agent only sees the eventual `transactionHash`.

The agent's interface is just HTTP plus a signed payload. The merchant could swap facilitators, schemes, or chain-side details and the agent's code would still work.

## What the server never knows

- The agent's private key.
- The agent's bundler or paymaster URLs (the agent talks to those itself when constructing the UserOp for `aa-native`).
- Anything about the agent's account model beyond `userOp.sender` (the SCW address).

## Trust model

The merchant trusts the facilitator's `/verify` result and the bundler's UserOp receipt. A merchant that needs stronger settlement assurance can independently re-read `eth_getTransactionReceipt` and the `ReceiptLog` event from the settlement contract before serving the response. See [Settlement finality](/whitepaper.pdf) (whitepaper §5.4).

The agent trusts that the `PAYMENT-REQUIRED` headers in 402 responses describe what the merchant will actually settle. A merchant that emits one set of requirements and tries to settle a different amount is rejected at the verifier (`spec_mismatch`).


---

# Facilitator

> The service that verifies and settles x402 payment payloads on behalf of merchants.

The facilitator is a stateless HTTP service that does two things on behalf of merchants: it **verifies** payment payloads and it **submits** them to the chain. Merchants delegate to it so they can accept paid traffic without writing chain-specific code.

## The HTTP surface

Three endpoints, plus a health check.

- `GET /supported` — advertises the schemes and assets the facilitator handles.
- `POST /verify` — checks that a payload binds to a merchant's `PaymentRequirements`. Returns `{isValid: true, payer}` or `{isValid: false, invalidReason, details?}`.
- `POST /settle` — re-verifies, then submits the operation to the chain. Returns `SettleResult` (success or error).

`/verify` is read-only; `/settle` is not. Merchants commonly verify before invoking the protected handler and settle after the handler returns 2xx, so they don't pay for settlement when their handler fails.

## What `/verify` checks

For an `aa-native` payload, the verifier:

1. Decodes the V2 envelope.
2. Decodes the inner `userOp` and `settlementCallSpec`.
3. ABI-decodes `userOp.callData` to a `SettlementContract.settle(merchant, token, amount, requestHash)` invocation. Both `SimpleAccount.execute(...)` and `SimpleAccount.executeBatch(...)` are accepted; for `executeBatch` the verifier finds the entry whose data decodes to `settle`.
4. Asserts that the decoded `settle` arguments equal `settlementCallSpec` field-for-field.
5. Asserts that `settlementCallSpec` matches the merchant's `PaymentRequirements` (merchant address, token, amount).
6. Checks the off-chain replay registry for `requestHash` collisions.

The full validation rules and the error codes are in the [whitepaper §2.4](/whitepaper.pdf). The error code list is on the [Errors reference page](/docs/reference/errors).

## What `/settle` does

`/settle` is idempotent on `requestHash`. The flow:

1. **Claim** the `requestHash` in the off-chain registry as `in_flight`. If it is already `settled`, return the original `txHash` immediately. If it is already `in_flight`, return `errorCode: "in_flight"`.
2. **Re-verify** with the same checks as `/verify`. Releases the in-flight claim on failure.
3. **Submit** the UserOp via `eth_sendUserOperation` on the bundler. Captures the returned `userOpHash`.
4. **Wait** for the bundler to return a receipt via `eth_getUserOperationReceipt`. The settlement contract emits `ReceiptLog` on success.
5. **Complete** the registry entry with the bundler-returned `transactionHash`.

A second `/settle` call with the same `requestHash` returns the original tx hash without re-submitting. In production tests this short-circuit completes in single-digit milliseconds versus several seconds for the original bundler round-trip.

## Auth

Merchants authenticate to the facilitator with an HMAC-signed bearer token in `Authorization: Bearer <hmac>`. This authentication scheme is a facilitator-implementation detail and is not specified by x402.

The reference public Playground shares one rate-limited token across its public endpoints. Per-merchant tokens are issued out-of-band for production merchants.

## Scheme support

The reference NERO 402 facilitator handles both `aa-native` and `exact`. `/supported` lists both:

```json
{
  "x402Version": 2,
  "schemes": [
    {"scheme":"exact",     "networks":["eip155:1689"], "assets":["0x...USDC", "0x...USDT"]},
    {"scheme":"aa-native", "networks":["eip155:1689"], "assets":["0x...USDC", "0x...USDT"]}
  ]
}
```

A merchant that wants to accept both can advertise both in its `paymentRequirements` array. The client picks whichever it can satisfy.

## Self-hosting

The reference facilitator is at [`apps/facilitator/`](https://github.com/nerochain/nero-x402/tree/main/apps/facilitator). It runs on Node 20+, uses Hono, and is small enough to deploy on Vercel Functions, Fly.io, Railway, or any Node host.

A self-hosted facilitator handles its own paymaster relationship and bears the gas cost for `aa-native` settlements it submits. Where the public NERO 402 facilitator is single-tenant and operated by the project, self-hosted deployments are per-merchant.


---

# HTTP 402

> How x402 V2 uses the long-reserved 402 status code to gate paid resources over plain HTTP.

The 402 status code has been "reserved for future use" in the HTTP specification since 1991. The x402 protocol activates it: a server returns `402 Payment Required` when the client asks for a paid resource without paying, the client signs a payment payload, and the server delivers the resource on retry.

## Three headers, three documents

The wire format adds three HTTP headers on top of normal requests and responses. Each carries a base64url-encoded JSON document.

- **`PAYMENT-REQUIRED`** — set by the merchant on the 402 response. Lists the schemes and prices the merchant accepts.
- **`PAYMENT-SIGNATURE`** — set by the client on the retried request. Carries the signed payment payload.
- **`PAYMENT-RESPONSE`** — set by the merchant on the eventual 200 response. Carries the on-chain settlement receipt.

The base64url encoding lets the documents survive hop-by-hop infrastructure (proxies, ingress controllers, browser fetch APIs) without escape issues.

## A complete round-trip

```http
POST /api/llm HTTP/1.1
Host: x402.nerochain.io
Content-Type: application/json

{ "prompt": "Hello" }
```

```http
HTTP/1.1 402 Payment Required
Payment-Required: eyJ4NDAyVmVyc2lvbiI6Mi...    (base64url JSON)
Content-Type: application/json

{ "x402Version": 2, "accepts": [...] }
```

The decoded `accepts` list:

```json
[
  {
    "scheme": "aa-native",
    "network": "eip155:1689",
    "amount": "1000",
    "asset": "0x...",
    "payTo": "0x...",
    "maxTimeoutSeconds": 60
  }
]
```

The client then signs a payload that satisfies one of the entries and re-issues the request:

```http
POST /api/llm HTTP/1.1
Host: x402.nerochain.io
Payment-Signature: eyJ4NDAyVmVyc2lvbiI6Mi...    (base64url JSON)
Content-Type: application/json

{ "prompt": "Hello" }
```

On success:

```http
HTTP/1.1 200 OK
Payment-Response: eyJzdWNjZXNzIjp0cnVlLi...    (base64url JSON)
Content-Type: application/json

{ "completion": "Hi! How can I help?" }
```

The decoded `Payment-Response` contains `transactionHash`, `payer`, `amount`, `asset`, and the canonical settlement metadata.

## Why 402 and not a custom status

Reusing 402 is the whole point. Existing HTTP intermediaries (CDNs, gateways, observability tooling) treat 402 as a normal client error today; they do not strip the `Payment-*` headers, they pass the body through, and they log requests at the right severity. Inventing a new status code or a non-HTTP layer would break this.

## Schemes

The `scheme` field on each `accepts` entry names the settlement scheme. NERO 402's facilitator advertises two:

- `exact` — EIP-3009 `transferWithAuthorization` from an EOA. Compatible with unmodified upstream `@x402/fetch` clients.
- `aa-native` — paymaster-sponsored UserOp from an ERC-4337 SCW. Defined in [the aa-native scheme page](/docs/core-concepts/aa-native-scheme) and the [whitepaper](/whitepaper.pdf).

Schemes share the outer envelope (`x402Version`, `accepted`, `payload`, `extensions`); only the inner `payload` differs. New schemes are additive.


---

# Networks and tokens

> The chains and assets NERO 402's reference implementation supports.

The `aa-native` scheme is chain-agnostic by design. Any network with an ERC-4337 stack (`EntryPoint`, bundler, paymaster) can host a settlement contract and serve x402 payments. The reference implementation currently targets two networks.

## NERO Chain mainnet

| Property | Value |
|---|---|
| CAIP-2 | `eip155:1689` |
| Chain ID | `1689` |
| RPC URL | `https://rpc.nerochain.io` |
| Bundler RPC | `https://bundler-mainnet.nerochain.io` |
| Paymaster RPC | `https://paymaster-mainnet.nerochain.io` |
| EntryPoint | `0x5FF137D4b0FDCD49DcA30c7CF57E578a026d2789` (v0.6) |
| SimpleAccountFactory | `0x9406Cc6185a346906296840746125a0E44976454` |
| `SettlementContract` (proxy) | `0x5eCfc64f2339992668f555918674B604F97B412D` |
| Explorer | https://neroscan.io |

### Mainnet allowlisted assets

| Symbol | Address | Decimals | EIP-3009? |
|---|---|---|---|
| USDC.e | `0x97eec1c29f745dc7c267f90292aa663d997a601d` | 6 | ✓ |
| USDC.arb | `0x8712796136Ac8e0EEeC123251ef93702f265aa80` | 6 | ✓ |
| USDT | `0xff13a7a12fd485bc9687ff88d8ae1a6b655ab469` | 6 | ✗ |

## NERO Chain testnet

| Property | Value |
|---|---|
| CAIP-2 | `eip155:689` |
| Chain ID | `689` |
| RPC URL | `https://rpc-testnet.nerochain.io` |
| Bundler RPC | `https://bundler-testnet.nerochain.io` |
| Paymaster RPC | `https://paymaster-testnet.nerochain.io` |
| EntryPoint | `0x5FF137D4b0FDCD49DcA30c7CF57E578a026d2789` (v0.6) |
| SimpleAccountFactory | `0x9406Cc6185a346906296840746125a0E44976454` |
| `SettlementContract` (proxy) | `0x925dbba44570683ac8da99be08bc5ece8cf5a8c6` |
| Faucet | https://app.testnet.nerochain.io/faucet |
| Explorer | https://testnet.neroscan.io |

### Testnet allowlisted asset

| Symbol | Address | Decimals | Notes |
|---|---|---|---|
| DEMO-USDT | `0x9a2eabdecda3eae051bca75fbe71a3dbdb35f9d4` | 6 | Public `mint(address, uint256)` for self-faucet |

DEMO-USDT exposes a public `mint()` so any agent can self-faucet without a centralized drip. The `examples/learn-nero/` script auto-mints on first run if the SCW balance is below the call cost, gas-sponsored.

## EntryPoint version

NERO mainnet uses ERC-4337 v0.6, confirmed via `eth_supportedEntryPoints` on the bundler. `paymasterAndData` is a single `bytes` value, not the split form introduced in v0.7. The SDK targets v0.6; agents using a v0.7-shaped `UserOperation` will be rejected at verification with `invalid_inner_payload`.

## Adding a network

Adding a new chain requires:

1. An ERC-4337 deployment on the chain (EntryPoint, bundler, paymaster).
2. A fresh `SettlementContract` deployment with the chain's allowlisted assets.
3. The facilitator's configuration extended with the new network's RPCs and contract address.

The wire format treats the network identifier as opaque (CAIP-2). A facilitator handling multiple networks tracks one contract address per network.

## Adding a token

Tokens are added to the settlement contract's allowlist by the contract's owner. The current owner is multisig-controlled; a new asset listing involves a multisig transaction calling `setTokenAllowed(token, true)`.

For testing, deploy a new token on testnet, give it a public `mint()`, and add it to the testnet contract's allowlist. The reference DEMO-USDT is the canonical example.


---

# Paymaster

> How NERO Paymaster sponsors UserOp gas, removing the native-asset balance from the agent's responsibilities.

A paymaster is an ERC-4337 contract that pays gas for a `UserOperation` on behalf of the operation's sender. In NERO 402's `aa-native` flow, the paymaster is the reason an agent's SCW does not need to hold any NERO native — every paid call is end-to-end gas-sponsored.

## The shape of sponsorship

ERC-4337's UserOp envelope carries a `paymasterAndData` field. When non-empty, the bundler routes through a paymaster contract; the paymaster validates the operation, debits its own deposit at the EntryPoint, and lets the operation execute. The paymaster's bookkeeping is on chain; the agent does not need to know about it.

NERO operates a **type-0** paymaster: gas is sponsored unconditionally for operations approved by the paymaster API. (Other types pay gas in an ERC-20 token rather than free-of-charge; NERO 402's reference flow uses type-0.)

## Constructing a sponsored UserOp

The agent calls the paymaster API as part of building the operation. Concretely, in `@nerochain/x402-aa`:

```ts
builder.setPaymasterOptions({
  apikey: paymasterApiKey,
  rpc:    paymasterUrl,
  type:   "0",
});
```

The paymaster's middleware in the [`userop`](https://github.com/nerochain/aa-userop-sdk) SDK calls the paymaster RPC, receives a signed `paymasterAndData` blob, and inserts it into the UserOp before signing. The agent's owner key signs the operation; the paymaster's signature is independent.

## Operational implications

For agents:

- The SCW can be brand-new and undeployed. The first sponsored UserOp deploys the SCW (`initCode`) and settles in the same operation. Confirmed empirically against NERO mainnet.
- The agent never holds a native-asset balance. Wallet bookkeeping is just stablecoins.
- The agent is decoupled from native-gas price volatility.

For the paymaster operator (NERO, in v1):

- An API key is required. Issued from the [NERO AA Platform dashboard](https://docs.nerochain.io/en/developer-tools/aa-platform).
- Each key has a rate quota. Bundler-side limits cap sponsored throughput at roughly 100 rps per API key.
- The paymaster operator bears the native gas cost of every sponsored UserOp. It is up to the operator to recoup this from merchants out of band, or to absorb it as a network operating cost.

## Verifying gas sponsorship

The `agent-cost-test` example in the repo is a CLI that runs N paid calls and asserts the agent SCW's native-asset balance does not decrease across the run:

```
== invariants ==
  ✓ all calls returned 200
  ✓ total USDT spend == sum of receipts (0.002 == 0.002)
  ✓ total USDT spend == N × per-call price (0.002 == 0.002)
  ✓ agent SCW spent 0 NERO native (delta = 0.0 NERO)
```

See [`examples/agent-cost-test/`](https://github.com/nerochain/nero-x402/tree/main/examples/agent-cost-test).

## Paymaster abuse

A paymaster that sponsors UserOps is structurally exposed to abuse: a malicious agent could submit operations that pass simulation, get sponsored, then revert on chain in ways that consume gas without producing a useful settlement. The mitigations layered into the reference deployment are documented in the [whitepaper §5.3](/whitepaper.pdf): API-key quotas, bundler rate limits, facilitator-side rate limits, and the off-chain replay registry rejecting re-attempts before paymaster sign-off.

## Future directions

ERC-4337 paymasters have several other modes worth noting, even though `aa-native` v1 only uses type-0:

- **Type-1 (token paymaster).** Agent pays gas in an ERC-20 (often the same stablecoin used for the settlement). Useful when the paymaster operator does not want to absorb native gas costs.
- **Verifying paymaster with rules.** Paymaster validates application-specific predicates before sponsoring. For example: only sponsor UserOps whose callData targets a specific merchant.

Both modes are protocol-compatible with `aa-native` because the wire format treats the UserOp as opaque. A future facilitator could opt into either without a scheme change.


---

# Settlement contract

> The on-chain endpoint where aa-native payments land. Replay-protected, allowlist-gated, UUPS-upgradeable.

The `SettlementContract` is the on-chain piece of NERO 402. Every `aa-native` payment ends in a call to its `settle(...)` function. The contract is a single shared deployment used by every merchant; merchants are arguments to the call, not separate contracts.

## Function signature

```solidity
function settle(
  address merchant,
  address token,
  uint256 amount,
  bytes32 requestHash
) external payable nonReentrant whenNotPaused;
```

The function:

1. Reverts on zero values, unallowed tokens, and reused `requestHash`.
2. Marks `isSettled[requestHash] = true` (replay protection).
3. Calls `IERC20(token).safeTransferFrom(msg.sender, merchant, amount)`.
4. Post-checks that the merchant's balance increased by exactly `amount`.
5. Emits `ReceiptLog(merchant, msg.sender, token, amount, requestHash)`.

`msg.sender` is the paying SCW. The SCW must have approved the settlement contract for at least `amount` of `token` before the call. The reference SDK encodes the approval and the settlement in one `executeBatch([approve, settle])` UserOp, so they are atomic.

## State

```solidity
mapping(bytes32 requestHash => bool settled) public isSettled;
mapping(address token => bool allowed)        public isTokenAllowed;
uint256[48] private __gap;
```

`isSettled` is the authoritative replay registry — once a `requestHash` is `true`, the contract refuses to settle it again. `isTokenAllowed` is an owner-managed allowlist of the tokens the contract will accept transfers for. The `__gap` reserves storage for future upgrades.

## Replay protection

The `requestHash` field is a `keccak256` of `(merchantAddress, chainId, httpMethod, canonicalEndpoint, timestampBucket, clientNonce)`. The merchant address is part of the hash, so a payload signed for merchant A produces a different hash from one a malicious party would need to settle against merchant B. Because `isSettled` is global, the same hash never settles twice regardless of which merchant the call names.

## Upgrade pattern

The contract uses the OpenZeppelin v5 UUPS proxy pattern. An `ERC1967Proxy` is deployed in front of an upgradeable implementation. The implementation calls `_disableInitializers()` in its constructor so it can never be driven directly. `_authorizeUpgrade` is owner-only and rejects the zero address.

The upgrade authorization path adds non-trivial audit surface; the contract is currently pre-audit and will undergo external review before the v1.0 release.

## Custom errors

```solidity
error UnexpectedNativeValue();   // settle() called with msg.value != 0
error ZeroAddress();              // merchant or token is 0x0
error ZeroAmount();               // amount is 0
error ZeroRequestHash();          // requestHash is bytes32(0)
error TokenNotAllowed(address);   // token is not on the allowlist
error AlreadySettled(bytes32);    // requestHash has already been settled
```

These are the only revert paths. A reverted UserOp surfaces in the facilitator's `/settle` response as `errorCode: "user_op_failed"` with the surfaced reason.

## Deployment addresses

- **Mainnet** (`eip155:1689`):
  proxy `0x5eCfc64f2339992668f555918674B604F97B412D`,
  implementation `0xb7f16185619c476ce3fd3fd9e8b6186e340802f6`.

- **Testnet** (`eip155:689`):
  proxy `0x925dbba44570683ac8da99be08bc5ece8cf5a8c6`.

The proxy address is the only address agents and merchants need to know. Implementations may be upgraded behind it.

## Verifying settlements externally

A merchant who needs strong assurance can independently verify the on-chain state of any settlement by reading the `ReceiptLog` event:

```solidity
event ReceiptLog(
  address indexed merchant,
  address indexed payer,
  address indexed token,
  uint256 amount,
  bytes32 requestHash
);
```

The reference Playground's live ledger panel does exactly this — it polls `getLogs` on the settlement contract independently of the facilitator's reports.

The contract source is [`contracts/src/SettlementContract.sol`](https://github.com/nerochain/nero-x402/blob/main/contracts/src/SettlementContract.sol). The complete ABI is on the [Contract reference page](/docs/reference/contract).


---

# Wallet

> How agent wallets work in NERO 402, and why the SCW model unlocks stablecoin-only operation.

The wallet is the structure that holds the agent's funds and produces the signature on the payment payload. NERO 402 supports two wallet shapes, one per scheme.

## EOA (the `exact` scheme)

An externally-owned account is an Ethereum account whose key lives off-chain. Signing happens locally. The token's `transferWithAuthorization` path requires the recovered signer (`ecrecover` of `(v, r, s)`) to hold the source balance.

Pros: simple, no contract deployment, supported by every wallet library.

Cons: the EOA must hold the chain's native asset to pay gas (`exact` settlement is submitted by the facilitator's hot wallet, but if the agent ever needs to do anything on chain itself it needs gas). Most current EOAs also do not implement ERC-1271 fallback signing.

## ERC-4337 SCW (the `aa-native` scheme)

A smart contract wallet is an Ethereum account whose code is on-chain. The address is a CREATE2 deployment of an account contract that delegates signature validation to its own logic. In the canonical case (`SimpleAccount`), the account's owner is an EOA whose signature the account contract verifies.

The agent's signing flow:

1. The agent constructs a `UserOperation` whose `callData` invokes `SettlementContract.settle(...)`.
2. The agent signs the operation's hash with the SCW's owner key.
3. A bundler submits the operation through the canonical `EntryPoint` contract.
4. A paymaster sponsors the operation's gas.

The agent's SCW only ever needs to hold the **settlement asset** (USDT, USDC, or DEMO-USDT). It does not need NERO native. This is the operational simplification that makes `aa-native` worth defining.

## Counterfactual addresses

An SCW's address is determined by its factory + salt + owner EOA. The chain only stores the contract once it has been deployed by an `initCode`-bearing UserOp, but the address is computable before deployment. Funds can be sent to a counterfactual SCW; they sit at that address until the SCW deploys and starts spending them.

NERO 402's first paid call from a fresh SCW deploys the SCW and settles in the same UserOp, sponsored by the paymaster end-to-end. The agent observes only a single HTTP round-trip and ends up with a deployed wallet plus a paid response.

## How the SDK constructs the wallet

`@nerochain/x402-aa`'s `aaNativeSigner({signer})` wraps an `ethers.Wallet` (or `ethers.HDNodeWallet`) as the SCW owner. Internally it uses the [`userop`](https://github.com/nerochain/aa-userop-sdk) SDK and the canonical NERO `SimpleAccountFactory` to derive the SCW address and prepare UserOps.

```ts
const wallet = new ethers.Wallet(privateKey);
const signer = aaNativeSigner({
  signer: wallet,
  rpcUrl, bundlerUrl, paymasterUrl, paymasterApiKey,
  settlementContract,
});
```

The SCW address is reproducible from the EOA + factory. Two runs of the same key produce the same SCW address.

## Web3Auth-derived owners

For browser-based agents, the playground uses Web3Auth to obtain a `JsonRpcSigner` from a social login. That signer is passed to `aaNativeSigner` in place of an `ethers.Wallet`. The end-user's social-login session backs the SCW's owner key; the SCW itself behaves identically.

See the [Web3Auth integration guide](/docs/guides/web3auth-integration) for the full pattern.

## Session keys

The `SimpleAccount` contract used by the reference SDK requires the owner to sign every UserOp. Alternative ERC-4337 account contracts (Kernel, Safe with modules, ZeroDev, others) support session keys that delegate scoped spending to a separate key — for example, "may only sign UserOps targeting `SettlementContract.settle` for amounts up to 10 USDT/day". Plugging these in is a factory swap; the wire format is unaffected. See the [Session keys & spending caps](/docs/advanced/session-keys) page.


---

# Quickstart for agents

> Make a paid call to an x402-gated endpoint from a Node script in 30 lines.

This guide walks through making an x402 paid call from an autonomous agent — a script, an LLM agent, or a browser tab. By the end you will have a Node script that pays a tiny amount of DEMO-USDT for a gated API response, with gas sponsored by the paymaster.

The complete runnable version of this script lives in the repo at [`examples/learn-nero/`](https://github.com/nerochain/nero-x402/tree/main/examples/learn-nero).

## Prerequisites

- An EOA private key. Generate one with `openssl rand -hex 32`. The corresponding SCW is derived deterministically from this key plus the canonical SimpleAccount factory.
- A NERO Paymaster API key from the [NERO AA Platform dashboard](https://docs.nerochain.io/en/developer-tools/aa-platform).
- The packages installed (see [Installation](/docs/getting-started/installation)).

The agent's SCW does **not** need a NERO native balance. The paymaster sponsors gas. On testnet the SCW does not even need DEMO-USDT to start — the script auto-mints from a public `mint()` on first run.

## The minimal flow

```ts
import { ethers } from "ethers";
import { x402Fetch, readSettlementReceipt } from "@nerochain/x402-client";
import { aaNativeSigner } from "@nerochain/x402-aa";

const wallet = new ethers.Wallet(process.env.NERO_PRIVATE_KEY!);

const f = x402Fetch({
  signer: aaNativeSigner({
    signer: wallet,
    rpcUrl:           "https://rpc-testnet.nerochain.io",
    bundlerUrl:       "https://bundler-testnet.nerochain.io",
    paymasterUrl:     "https://paymaster-testnet.nerochain.io",
    paymasterApiKey:  process.env.NERO_PAYMASTER_API_KEY!,
    settlementContract: "0x925dbba44570683ac8da99be08bc5ece8cf5a8c6",
  }),
});

const res = await f("http://localhost:4000/api/nero-knowledge", {
  method: "POST",
  headers: { "content-type": "application/json" },
  body: JSON.stringify({ question: "How does the paymaster work?" }),
});

console.log(res.status, await res.json());

const receipt = readSettlementReceipt(res);
if (receipt) {
  console.log("settled:", receipt.transactionHash);
  console.log("paid   :", ethers.formatUnits(receipt.amount, 6), "DEMO-USDT");
}
```

That is the entire payment loop. `x402Fetch` is a `fetch`-API-compatible function that:

1. Issues the request.
2. If it receives a 402 with a `PAYMENT-REQUIRED` header, asks the signer to construct a paymaster-sponsored UserOp targeting the settlement contract.
3. Re-issues the request with the signed payload in the `PAYMENT-SIGNATURE` header.
4. Returns the eventual 200 response with a `PAYMENT-RESPONSE` header that decodes to a structured settlement receipt.

## What happens behind the scenes

| Step | What runs | Where |
|---|---|---|
| Request 1 | Plain `fetch` | Agent → merchant |
| 402 response | Merchant middleware emits `PAYMENT-REQUIRED` | Merchant |
| Sign UserOp | `aaNativeSigner` builds + sponsors + signs the UserOp | Agent (in-process) |
| Request 2 | `fetch` with `PAYMENT-SIGNATURE` | Agent → merchant |
| `/verify` | Merchant middleware forwards to facilitator | Merchant → facilitator |
| `/settle` | Facilitator submits via bundler | Facilitator → bundler → chain |
| 200 response | Merchant attaches `PAYMENT-RESPONSE` (settlement receipt) | Merchant → agent |

The agent never sees the bundler or the facilitator directly. They are merchant-side concerns; the agent only signs the UserOp and re-issues the HTTP request.

## Pointing at mainnet

Swap the testnet URLs and contract for their mainnet equivalents:

```ts
rpcUrl:           "https://rpc.nerochain.io",
bundlerUrl:       "https://bundler-mainnet.nerochain.io",
paymasterUrl:     "https://paymaster-mainnet.nerochain.io",
settlementContract: "0x5eCfc64f2339992668f555918674B604F97B412D",
```

Mainnet has no auto-mint. Send real USDT to the SCW address before running. The SCW address is deterministic; the script in `examples/learn-nero/` prints it so you know where to fund.

## Next

- [Quickstart for merchants](/docs/getting-started/merchants) — the other side of the same flow.
- [SDK overview](/docs/sdk/overview) — the five packages, when to use which.
- [Whitepaper](/whitepaper.pdf) — the protocol's normative specification.


---

# Installation

> Install the @nerochain/x402-* packages.

The NERO 402 SDK is published as five packages under the `@nerochain/` scope. Each package is independently installable; you only pull in what you use.

## Choose the packages you need

| Package | When to install it |
|---|---|
| `@nerochain/x402-types` | Always (transitively included by the others; install directly only if you build your own client/server adapter). |
| `@nerochain/x402-server` | You are a merchant gating an HTTP endpoint behind payment. |
| `@nerochain/x402-client` | You are an agent making paid calls. |
| `@nerochain/x402-aa` | You sign payments from an ERC-4337 smart contract wallet (the `aa-native` scheme). |
| `@nerochain/x402-extensions` | You want client-side idempotency or signed access tokens for cached access after a paid call. |

## Agent-side install

```bash
pnpm add @nerochain/x402-client @nerochain/x402-aa ethers
```

## Merchant-side install (Express)

```bash
pnpm add @nerochain/x402-server
```

Adapters for Hono, Fastify, and Next.js App Router are subpath imports of the same package — no separate install.

## Requirements

- **Node 20+** for the runtime.
- **TypeScript 5+** if you are using TypeScript directly. The packages ship `.d.ts` types.
- **`ethers` v6** for the agent side (the SDK accepts an `ethers.Wallet` or `ethers.HDNodeWallet`).

## Verifying the install

After installing, type-check that the packages resolve:

```bash
node -e "console.log(require('@nerochain/x402-client').x402Fetch.toString().slice(0, 60))"
```

You should see the start of the `x402Fetch` factory function. From there, head to the [agent quickstart](/docs/getting-started/agents) or the [merchant quickstart](/docs/getting-started/merchants).


---

# Quickstart for merchants

> Gate an HTTP endpoint behind x402 payment in any of Express, Hono, Fastify, or Next.js.

This guide walks through gating an HTTP endpoint behind a paid call. By the end your endpoint will return `402 Payment Required` to unpaid agents, accept a signed payment payload on retry, and deliver content only after the on-chain settlement succeeds.

A complete runnable version with both an Express server and an integration test is in [`examples/express-paid-api/`](https://github.com/nerochain/nero-x402/tree/main/examples/express-paid-api).

## What you need

- A facilitator URL the middleware can call. For local development, run the [reference facilitator](https://github.com/nerochain/nero-x402/tree/main/apps/facilitator) on `:3000`. For production, point at `facilitator.x402.nerochain.io`.
- A merchant address that receives the settlement transfers. This is just an EOA or contract address you control on NERO Chain.
- The package: `pnpm add @nerochain/x402-server`.

## Express

```ts
import express from "express";
import { x402Express } from "@nerochain/x402-server/express";

const app = express();
app.use(express.json());

app.use(
  "/api/llm",
  x402Express({
    paymentRequirements: {
      scheme: "aa-native",
      network: "eip155:689",
      amount: "1000",                                          // 0.001 USDT (atomic units, 6 decimals)
      asset:   "0x9a2eabdecda3eae051bca75fbe71a3dbdb35f9d4",   // DEMO-USDT on NERO testnet
      payTo:   "0xYourMerchantAddress",
      maxTimeoutSeconds: 60,
    },
    facilitator: { url: "http://localhost:3000" },
    resource: { url: "/api/llm", description: "demo paid endpoint" },
  }),
  (req, res) => {
    res.json({ ok: true, payer: req.x402Payer, content: "demo response" });
  },
);

app.listen(4040);
```

The middleware does three things automatically:

1. On a request without a `PAYMENT-SIGNATURE` header, it returns 402 with the `paymentRequirements` payload.
2. On a request with a payload, it forwards to the facilitator's `/verify`. If verification fails, it returns 402 with the error code.
3. After your handler runs successfully, it forwards to `/settle` and attaches the `PAYMENT-RESPONSE` header with the on-chain receipt.

The handler runs only after verification has passed. Inside the handler, `req.x402Payer` is the SCW that paid.

## Hono

```ts
import { Hono } from "hono";
import { x402Hono } from "@nerochain/x402-server/hono";

const app = new Hono();

app.use(
  "/api/llm",
  x402Hono({ paymentRequirements, facilitator: { url } }),
);
app.post("/api/llm", (c) => c.json({ ok: true, payer: c.get("x402Payer") }));
```

## Fastify

```ts
import Fastify from "fastify";
import { x402Fastify } from "@nerochain/x402-server/fastify";

const app = Fastify();
app.register(x402Fastify, {
  prefix: "/api/llm",
  paymentRequirements,
  facilitator: { url },
});
app.post("/api/llm", async (req) => ({ ok: true, payer: req.x402Payer }));
```

## Next.js App Router

```ts
// app/api/llm/route.ts
import { x402Next } from "@nerochain/x402-server/next";

export const POST = x402Next(
  { paymentRequirements, facilitator: { url } },
  async (req) => Response.json({ ok: true }),
);
```

## Pricing and asset selection

`paymentRequirements.amount` is in atomic units (no decimal point). For a token with 6 decimals like USDT/USDC, `1000` is `0.001` of a token. The asset address must be on the allowlist of the configured `SettlementContract`. On NERO mainnet that's USDT (`0xff13a7a12fd485bc9687ff88d8ae1a6b655ab469`), USDC.e (`0x97eec1c29f745dc7c267f90292aa663d997a601d`), and USDC.arb (`0x8712796136Ac8e0EEeC123251ef93702f265aa80`); on testnet it's DEMO-USDT (`0x9a2eabdecda3eae051bca75fbe71a3dbdb35f9d4`).

To accept multiple schemes or assets, pass an array:

```ts
paymentRequirements: [
  { scheme: "aa-native", network: "eip155:689", amount: "1000", asset: USDT, payTo, maxTimeoutSeconds: 60 },
  { scheme: "exact",     network: "eip155:689", amount: "1000", asset: USDT, payTo, maxTimeoutSeconds: 60 },
],
```

The client picks whichever it can satisfy.

## Next

- [Facilitator concept](/docs/core-concepts/facilitator) — what `/verify` and `/settle` do.
- [Networks & tokens](/docs/core-concepts/networks) — supported assets and addresses.
- [Wire format reference](/docs/reference/wire-format) — the envelope shape.


---

# Delegated agent pattern

> Spawn a fresh ephemeral SCW, fund it once, let it loop through paid endpoints autonomously, then recover funds.

The "delegated agent" is the canonical x402 narrative: a user grants a fresh SCW some stablecoin spending budget, an agent runs autonomously against paid APIs from that SCW, and the user recovers any leftover funds at the end. This guide describes the pattern and points at the reference implementation in the Playground.

## Why delegate

In `aa-native`, every UserOp is signed by the SCW's owner key. If you want an autonomous agent to make paid calls without that owner being online, you need either:

1. To give the agent the owner's key (full delegation, full risk), or
2. To use a session-key-capable account contract that scopes the agent's spending (proper delegation, but requires non-canonical SCW logic — see [Session keys](/docs/advanced/session-keys)), or
3. To spawn a **fresh ephemeral SCW** owned by a fresh, throwaway key. The agent gets full control over that SCW, but the SCW only ever holds the budget the user funded it with.

The Playground uses option (3) for its in-browser delegated-agent demo. It is the simplest pattern that requires no SCW-side custom code.

## The flow

1. **Spawn.** Generate a fresh `ethers.Wallet.createRandom()` in the user's browser. Derive the SCW address from this fresh EOA + the canonical factory. The owner key lives only in browser memory.
2. **Fund.** From the user's main SCW, transfer some DEMO-USDT (or USDT, on mainnet) to the agent SCW. This is a paymaster-sponsored UserOp from the user's main SCW; one signature from the user, then it's in the agent SCW.
3. **Run.** The agent loops through a sequence of paid calls using the fresh wallet's `aaNativeSigner`. Every call is gas-sponsored; the agent SCW only spends the stablecoin.
4. **Despawn.** When the user is done, drain whatever DEMO-USDT remains in the agent SCW back to the user's main SCW. This is a paymaster-sponsored UserOp from the agent SCW. After the drain succeeds, the agent's owner key is forgotten.

The whole flow is in the Playground at `/playground`. The implementation is `apps/playground/src/components/agent-panel.tsx`.

## Risks of ephemeral SCW delegation

- **Browser-only key.** If the user refreshes the page, the agent's owner key is gone. Funds in the agent SCW are stuck.
- **No spending caps.** The agent can spend the full balance on any allowed endpoint. The cap is the funding amount, not a per-call limit.
- **No revocation other than draining.** You can't pause the agent without taking back the funds.

For a production multi-user deployment, the proper answer is session keys with on-chain caps and revocation. The ephemeral SCW pattern is good for demos and trusted-environment workflows where the user funds the agent themselves.

## Multi-call task pattern

The Playground's "Quote 6 markets" task is six sequential `/exchange-rate` calls. The reference loop:

```ts
const f = x402Fetch({ signer: aaNativeSigner({ /* agent's signer */ }) });

for (const call of task.calls) {
  const res = await f(`/api/${call.endpoint}`, {
    method: "POST",
    headers: { "content-type": "application/json" },
    body: JSON.stringify(call.body),
  });
  const receipt = readSettlementReceipt(res);
  log.append({ endpoint: call.endpoint, txHash: receipt?.transactionHash, ... });
}
```

Each iteration is one independent paid call. Failures are isolated; one revert does not roll back earlier successful settlements. The Playground stops the loop on first error so the user is not surprised by a half-complete batch.


---

# MCP server with x402

> Wrap NERO 402 paid calls behind a Model Context Protocol server so an LLM can spend through it.

The Model Context Protocol (MCP) is the standardized way to expose tools to an LLM. Wrapping NERO 402 paid calls behind an MCP server lets an LLM agent use paid APIs through the same tool-calling interface it uses for everything else; the agent sees a tool, the tool internally pays for and forwards the request.

## What you build

An MCP server that exposes one or more "paid call" tools. When the LLM invokes a tool:

1. The MCP server constructs the underlying x402 paid call using `x402Fetch` and `aaNativeSigner`.
2. The agent SCW (server-side, owned by the operator) pays the merchant.
3. The merchant's response is returned to the LLM as the tool's output.

The LLM never sees a private key, a UserOp, or a transaction hash. From the LLM's perspective, the tool is just `query_nero_knowledge(question: string) -> string`.

## Setup

```bash
pnpm add @modelcontextprotocol/sdk @nerochain/x402-client @nerochain/x402-aa
```

A minimal MCP server with one paid tool:

```ts
import { Server } from "@modelcontextprotocol/sdk/server";
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio";
import { ethers } from "ethers";
import { x402Fetch } from "@nerochain/x402-client";
import { aaNativeSigner } from "@nerochain/x402-aa";

const wallet = new ethers.Wallet(process.env.NERO_PRIVATE_KEY!);
const f = x402Fetch({
  signer: aaNativeSigner({
    signer: wallet,
    rpcUrl, bundlerUrl, paymasterUrl, paymasterApiKey,
    settlementContract,
  }),
});

const server = new Server({ name: "nero-x402-mcp", version: "1.0.0" });

server.tool({
  name: "query_nero_knowledge",
  description: "Ask a question about NERO Chain. Costs 0.002 DEMO-USDT per call.",
  inputSchema: { type: "object", properties: { question: { type: "string" } }, required: ["question"] },
  async handler({ question }) {
    const res = await f("https://x402.nerochain.io/api/nero-knowledge", {
      method: "POST",
      headers: { "content-type": "application/json" },
      body: JSON.stringify({ question }),
    });
    const body = await res.json();
    return { content: [{ type: "text", text: body.answer }] };
  },
});

await server.connect(new StdioServerTransport());
```

## Connecting to Claude Desktop

Claude Desktop reads MCP server configuration from `~/Library/Application Support/Claude/claude_desktop_config.json`:

```json
{
  "mcpServers": {
    "nero-x402": {
      "command": "node",
      "args": ["/path/to/your/mcp-server/dist/index.js"],
      "env": {
        "NERO_PRIVATE_KEY": "0x...",
        "NERO_PAYMASTER_API_KEY": "..."
      }
    }
  }
}
```

After restart, Claude can call `query_nero_knowledge` as a tool. Each invocation is one paid call against the live NERO 402 stack.

## Cost controls

A long-running agent should not have unbounded spending power. Practical safeguards:

- **Cap funding.** Only fund the SCW with the budget you're willing to lose to LLM mistakes.
- **Per-tool authorization.** Wrap the tool handler with a check that the LLM's request is sensible before paying.
- **Logging.** Record every settled call's `transactionHash`, the LLM's prompt, and the eventual response. Useful for debugging the LLM's spending patterns.

The session-key pattern (see [Session keys](/docs/advanced/session-keys)) gives chain-enforced spending caps and is the right answer for a serious deployment.


---

# Upstream interoperability

> Use unmodified Coinbase x402 clients against the NERO 402 facilitator.

NERO 402 was deliberately built to interoperate with the upstream `@x402/core@2.11.0` reference implementation. Anywhere both sides agree on the V2 envelope and the `exact` scheme, NERO 402's facilitator and the Coinbase reference client work together unmodified.

## What works out of the box

- **Coinbase `@x402/fetch` client → NERO 402 merchant middleware.** A client built against `@x402/core` can send `exact`-scheme payloads to a merchant using `@nerochain/x402-server`. Verified by the integration test at `examples/express-paid-api/src/interop.test.ts`.
- **`@nerochain/x402-server` middleware → upstream facilitator.** A merchant using `@nerochain/x402-server` can be configured to point at any facilitator that speaks the V2 wire format, including upstream reference deployments.
- **Settlement receipts.** The `PAYMENT-RESPONSE` body matches `@x402/core`'s `SettlementResultSchema`. Upstream clients can parse our receipts.

## What does not interoperate (and why)

- **`aa-native` is NERO 402-defined.** Upstream `@x402/fetch` does not yet know the scheme name. An upstream client cannot pay an `aa-native`-only merchant. Workaround: merchants offer both schemes in `accepts[]` so upstream clients fall back to `exact`.
- **Scheme-specific inner payloads.** The `payload` field is opaque per the spec; each scheme defines its own inner shape. Cross-scheme interop is by definition impossible.

## Enabling dual-scheme acceptance

The reference Playground accepts only `aa-native`. To accept both `aa-native` and `exact` from the same endpoint, list both:

```ts
paymentRequirements: [
  {
    scheme: "aa-native",
    network: "eip155:1689",
    amount: "1000",
    asset: USDT,
    payTo: MERCHANT,
    maxTimeoutSeconds: 60,
  },
  {
    scheme: "exact",
    network: "eip155:1689",
    amount: "1000",
    asset: USDT,
    payTo: MERCHANT,
    maxTimeoutSeconds: 60,
  },
],
```

The client picks whichever it can satisfy. `@x402/fetch` from upstream picks `exact`; `@nerochain/x402-client` with the `aa-native` signer picks `aa-native`.

## Reference facilitator support for `exact`

The reference NERO 402 facilitator handles both schemes. The `exact` scheme requires a hot-wallet submitter (the facilitator's own EOA) that holds NERO native and the relevant tokens; configure this via the `EXACT_SUBMITTER_PRIVATE_KEY` environment variable. Without it, `exact`-scheme settlements return `unsupported_scheme`.

## Conformance test

The integration test at `examples/express-paid-api/src/interop.test.ts` is the canonical proof of round-trip compatibility. It uses `@x402/core@2.11.0` to parse the reference middleware's 402 responses and submits Coinbase-format `PaymentPayload`s through the reference middleware. The test runs in under a second and is part of the workspace's standard `pnpm test` invocation.

This test caught one wire-format divergence during development (a field-name mismatch) and exists specifically to catch the next one.

## Migrating an existing `exact` deployment to `aa-native`

There is no "migration" in the sense of replacing one with the other. The two schemes coexist. To extend an existing `exact` merchant to also accept `aa-native`:

1. Deploy a `SettlementContract` on the merchant's network (or use the reference NERO Chain deployment).
2. Add an `aa-native` entry to the merchant's `paymentRequirements[]`.
3. Use a facilitator that supports both schemes (the reference one does).

Existing `exact` clients keep working. New SCW-based clients can pick `aa-native`.


---

# Web3Auth integration

> Use Web3Auth as the EOA owner behind an ERC-4337 SCW for NERO 402 payments.

The reference Playground uses Web3Auth for social-login wallets: a user signs in with Google, X, or Discord; the resulting key is an EOA that owns an SCW; the SCW is the paying account in `aa-native`. This guide shows how to wire that flow into your own app.

## Stack

- `@web3auth/modal` — the social-login modal and embedded MPC signer.
- `wagmi` + `@tanstack/react-query` — connector glue (Web3Auth ships a Wagmi adapter).
- `ethers` — converts the Web3Auth provider into a signer the SDK can use.
- `@nerochain/x402-client` + `@nerochain/x402-aa` — the payment surface.

## Bridging Web3Auth → ethers signer

Once Web3Auth has connected, get an `ethers.JsonRpcSigner` from its provider:

```ts
import { BrowserProvider } from "ethers";
import { useWeb3Auth } from "@web3auth/modal/react";

const { provider } = useWeb3Auth();
const browser = new BrowserProvider(provider);
const signer = await browser.getSigner();
```

That `signer` becomes the `signer` argument to `aaNativeSigner`. The `ethers.Wallet | ethers.HDNodeWallet` type signature is conservative — a `JsonRpcSigner` works at runtime, just cast through `unknown`:

```ts
import { aaNativeSigner } from "@nerochain/x402-aa";
import type { Wallet as EthersWallet } from "ethers";

const aaSigner = aaNativeSigner({
  signer: signer as unknown as EthersWallet,
  rpcUrl, bundlerUrl, paymasterUrl, paymasterApiKey,
  settlementContract,
});
```

The Playground's `useWallet` hook in `apps/playground/src/hooks/use-wallet.ts` is the reference implementation.

## Deriving the SCW address

The SCW is determined by the EOA + the canonical `SimpleAccountFactory` + a salt (`0` is fine). Once you have the signer:

```ts
import { Presets } from "userop";

const builder = await Presets.Builder.SimpleAccount.init(
  signer,
  rpcUrl,
  { overrideBundlerRpc: bundlerUrl },
);
const scwAddress = builder.proxy?.address;
```

Display the SCW address to the user before they pay. Before the first UserOp the SCW does not exist on chain, but the address is still computable; this is the standard ERC-4337 counterfactual addressing pattern.

## Funding flow

For testnet, the Playground exposes a "Mint 10 DEMO-USDT" button that constructs a paymaster-sponsored UserOp calling DEMO-USDT's public `mint(address, uint256)`. The reference implementation is in `apps/playground/src/components/wallet-panel.tsx`.

For mainnet, send real USDT to the SCW address by any means (transfer from another wallet, exchange withdrawal, etc.). The funds sit at the counterfactual address until the SCW deploys.

## What changes vs. a private-key wallet

- **Key custody.** With a raw `ethers.Wallet`, your app holds the key. With Web3Auth, the user's social-login session backs the key (MPC-style; the key is sharded between Web3Auth and the user's session).
- **Refresh resilience.** A Web3Auth-derived signer is restored automatically across page reloads as long as the user's session is alive.
- **Owner-key visibility.** The application code never sees raw private-key bytes. Signing happens through the Web3Auth provider's `personal_sign` / `eth_signTypedData_v4` interfaces.

The SCW behaves identically in both cases; the difference is purely in how the EOA owner is custodied.


---

# SettlementContract reference

> ABI, storage layout, and deployment addresses for SettlementContract.sol.

The `SettlementContract` is the on-chain endpoint of every `aa-native` payment. This page is the contract's reference card. The conceptual overview is on the [Settlement contract concept page](/docs/core-concepts/settlement-contract).

## Deployment addresses

| Network | Proxy | Implementation |
|---|---|---|
| NERO mainnet (`eip155:1689`) | `0x5eCfc64f2339992668f555918674B604F97B412D` | `0xb7f16185619c476ce3fd3fd9e8b6186e340802f6` |
| NERO testnet (`eip155:689`) | `0x925dbba44570683ac8da99be08bc5ece8cf5a8c6` | (proxy implementation address) |

The proxy is the address callers reference. Implementation addresses change on upgrade.

## Public interface

### `settle(address merchant, address token, uint256 amount, bytes32 requestHash)`

Settles one payment. Reverts on:

| Condition | Custom error |
|---|---|
| `msg.value != 0` | `UnexpectedNativeValue()` |
| `merchant == address(0)` | `ZeroAddress()` |
| `token == address(0)` | `ZeroAddress()` |
| `amount == 0` | `ZeroAmount()` |
| `requestHash == bytes32(0)` | `ZeroRequestHash()` |
| `!isTokenAllowed[token]` | `TokenNotAllowed(address token)` |
| `isSettled[requestHash]` | `AlreadySettled(bytes32 requestHash)` |
| Reentrancy guard tripped | (`ReentrancyGuardReentrantCall()`) |
| Contract is paused | (`EnforcedPause()`) |

After validation, `isSettled[requestHash]` is set to `true`, then `IERC20(token).safeTransferFrom(msg.sender, merchant, amount)` runs. The contract post-checks that the merchant's balance increased by exactly `amount`. On success, `ReceiptLog` is emitted.

`msg.sender` is the paying SCW. It must have approved the contract for `amount` of `token` before the call.

### View functions

```solidity
mapping(bytes32 requestHash => bool settled) public isSettled;
mapping(address token => bool allowed)        public isTokenAllowed;
```

### Owner-only functions

```solidity
function setTokenAllowed(address token, bool allowed) external onlyOwner;
function pause()   external onlyOwner;
function unpause() external onlyOwner;
function _authorizeUpgrade(address newImplementation) internal override onlyOwner;
```

## Events

```solidity
event ReceiptLog(
  address indexed merchant,
  address indexed payer,
  address indexed token,
  uint256 amount,
  bytes32 requestHash
);
```

Emitted on every successful settlement. The three indexed arguments allow efficient `getLogs` filtering by merchant, payer, or token.

## ABI fragments (TypeScript)

```ts
const SETTLEMENT_ABI = [
  "function settle(address merchant, address token, uint256 amount, bytes32 requestHash) external payable",
  "function isSettled(bytes32 requestHash) view returns (bool)",
  "function isTokenAllowed(address token) view returns (bool)",
  "event ReceiptLog(address indexed merchant, address indexed payer, address indexed token, uint256 amount, bytes32 requestHash)",
  "error UnexpectedNativeValue()",
  "error ZeroAddress()",
  "error ZeroAmount()",
  "error ZeroRequestHash()",
  "error TokenNotAllowed(address token)",
  "error AlreadySettled(bytes32 requestHash)",
] as const;
```

## Indexing settlements

A merchant or external indexer can read all settlements without querying the facilitator:

```ts
import { createPublicClient, http, parseAbiItem } from "viem";

const RECEIPT_LOG = parseAbiItem(
  "event ReceiptLog(address indexed merchant, address indexed payer, address indexed token, uint256 amount, bytes32 requestHash)",
);

const logs = await client.getLogs({
  address: SETTLEMENT_CONTRACT,
  event: RECEIPT_LOG,
  fromBlock: BigInt(0),
  toBlock: "latest",
});
```

The reference Playground's live ledger panel uses exactly this pattern.

## Source

The contract source is at [`contracts/src/SettlementContract.sol`](https://github.com/nerochain/nero-x402/blob/main/contracts/src/SettlementContract.sol). The interface is at [`contracts/src/interfaces/ISettlement.sol`](https://github.com/nerochain/nero-x402/blob/main/contracts/src/interfaces/ISettlement.sol). The deployment scripts are in `contracts/script/`.


---

# Error codes

> Stable identifier strings returned by the verifier and the settler.

Both the verifier (`/verify`) and the settler (`/settle`) return string error identifiers that merchants and SDKs can match on programmatically. The codes are stable; changing one is a breaking change.

`(V)` indicates the code may be returned by `/verify`. `(S)` indicates `/settle`. `(V, S)` indicates both.

## Verification + settlement codes

- **`invalid_envelope`** *(V)* — `paymentPayload` does not match the V2 envelope schema.
- **`unsupported_scheme`** *(V, S)* — the facilitator does not handle this scheme.
- **`requirements_mismatch`** *(V, S)* — the `accepted` block does not match the merchant's `paymentRequirements`.
- **`network_mismatch`** *(V)* — `accepted.network` differs from the merchant's requirement.
- **`amount_mismatch`** *(V)* — `accepted.amount` differs from the merchant's requirement.
- **`asset_mismatch`** *(V)* — `accepted.asset` differs from the merchant's requirement.
- **`payTo_mismatch`** *(V)* — `accepted.payTo` differs from the merchant's requirement.
- **`invalid_inner_payload`** *(V)* — `payload.userOp` or `payload.settlementCallSpec` is malformed.
- **`calldata_decode_failed`** *(V)* — `userOp.callData` does not decode to `execute(...)` or to an `executeBatch(...)` containing a `settle(...)` invocation.
- **`spec_mismatch`** *(V)* — the decoded `settle` arguments differ from `payload.settlementCallSpec`.
- **`replay`** *(V, S)* — the `requestHash` has already been settled.

## Settlement-only codes

- **`in_flight`** *(S)* — another settlement for this `requestHash` is in progress. Caller should retry after the indicated `Retry-After` interval.
- **`bundler_error`** *(S)* — the bundler rejected the UserOp. Causes include rate-limit rejection, simulation revert, and RPC error.
- **`user_op_failed`** *(S)* — the UserOp executed on chain but reverted. The `message` field carries the surfaced revert reason.
- **`receipt_timeout`** *(S)* — the bundler did not return a receipt within the configured deadline. The UserOp may still settle later; idempotency on `requestHash` ensures a retry will not double-spend.

## Internal

- **`internal_error`** *(V, S)* — facilitator-side fault. The client SHOULD retry once before treating this as a hard failure.

## Reserved

Codes outside this list are reserved. New scheme implementations and new failure modes SHOULD allocate a new code rather than overload an existing one.

## Where the codes appear

For `/verify`: `{isValid: false, invalidReason: "...", details?: ...}`. The `details` field, when present, carries machine-readable specifics (a Zod issue list for envelope errors, a sub-mismatch identifier for `spec_mismatch`).

For `/settle`: `{success: false, x402Version: 2, errorCode: "...", message: "..."}`. The `message` field is human-readable; do not match programmatically on it.

## Programmatic matching example

```ts
const settle = await fetch(facilitatorUrl + "/settle", { ... }).then(r => r.json());

if (settle.success) {
  // happy path
} else {
  switch (settle.errorCode) {
    case "in_flight":
      return retryAfter(...);
    case "user_op_failed":
      return surfaceRevert(settle.message);
    case "bundler_error":
    case "receipt_timeout":
      return retryWithBackoff(...);
    case "replay":
      // already settled — no further action; record the original txHash if possible
      break;
    default:
      // unknown codes are reserved and may be added in future versions
      log.warn("unknown settle errorCode", settle.errorCode, settle.message);
  }
}
```


---

# Whitepaper

> The protocol's normative specification. Wire format, validation rules, security model.

The full normative specification for the `aa-native` scheme is published as a whitepaper (PDF). It is the authoritative source for any conformance question.

[Download the whitepaper (PDF, ~280 KB, 16 pages)](/whitepaper.pdf)

## What's inside

1. **Background.** The x402 V2 protocol; why ERC-4337 accounts cannot satisfy `exact`; the two motivations for `aa-native`.
2. **The aa-native scheme.** Payload format, wire-format integration, `requestHash` derivation, verification rules, settlement procedure, and the complete error code list.
3. **Comparison to `exact`.** Side-by-side table plus prose on operational simplicity and trust assumptions.
4. **Reference implementation.** `SettlementContract.sol`, the facilitator service, and the four-package SDK suite.
5. **Security considerations.** Replay protection (on-chain and off-chain), cross-merchant replay, paymaster abuse, settlement finality, refund posture.
6. **Future work and standardization.** Multi-chain deployment, per-merchant settlement contracts, session keys, and the path to upstream standardization through `coinbase/x402#639`.

The two appendices are a glossary of the AA and x402 terms used throughout, and a reference list of every external standard and document the spec relies on (RFC 2119, ERC-4337, EIP-3009, x402 V2 transport, NERO AA platform docs).

## Citing

The whitepaper version printed on the title page is the canonical reference. When citing the spec in upstream conversations, link directly to the PDF; when referring to a specific clause, cite the section number (e.g., "see whitepaper §2.4 for the full validation rules").

## Source

The whitepaper source is in the project repo at [`docs/whitepaper/whitepaper.md`](https://github.com/nerochain/nero-x402/blob/main/docs/whitepaper/whitepaper.md). It builds to PDF via Pandoc + Typst (`make pdf` in that directory). The protocol-flow figure is generated from a D2 diagram source at `docs/whitepaper/figures/protocol-flow.d2`.


---

# Wire format

> The HTTP headers and JSON envelope shapes used by x402 V2 and the aa-native scheme.

This page enumerates the wire-format JSON shapes for quick lookup. The full normative definitions are in the [whitepaper §2](/whitepaper.pdf).

## HTTP headers

| Header | Direction | Carries (base64url JSON) |
|---|---|---|
| `PAYMENT-REQUIRED` | server → client (on 402) | `PaymentRequired` |
| `PAYMENT-SIGNATURE` | client → server (on retry) | `PaymentPayload` |
| `PAYMENT-RESPONSE` | server → client (on 200) | `SettlementResponse` |

Header names are case-insensitive in HTTP; the canonical casing is uppercase with dashes (`PAYMENT-REQUIRED`). Implementations should accept either case when reading.

## `PaymentRequired` (the 402 body)

```json
{
  "x402Version": 2,
  "resource": {
    "url": "/api/llm",
    "description": "demo paid endpoint"
  },
  "accepts": [
    {
      "scheme": "aa-native",
      "network": "eip155:1689",
      "amount": "1000",
      "asset": "0x...",
      "payTo": "0x...",
      "maxTimeoutSeconds": 60
    }
  ]
}
```

`accepts[]` is a list. Multi-scheme or multi-asset merchants list all options; the client picks one.

## `PaymentPayload` (the retry body)

```json
{
  "x402Version": 2,
  "accepted": {
    "scheme": "aa-native",
    "network": "eip155:1689",
    "amount": "1000",
    "asset": "0x...",
    "payTo": "0x...",
    "maxTimeoutSeconds": 60
  },
  "payload": { /* scheme-specific */ },
  "extensions": null
}
```

The `accepted` block repeats one entry from the merchant's `accepts[]`. The `payload` field is opaque per the V2 spec; each scheme defines its inner shape.

## `payload` for `aa-native`

```json
{
  "userOp": {
    "sender": "0x...",
    "nonce": "0x...",
    "initCode": "0x",
    "callData": "0x...",
    "callGasLimit": "...",
    "verificationGasLimit": "...",
    "preVerificationGas": "...",
    "maxFeePerGas": "...",
    "maxPriorityFeePerGas": "...",
    "paymasterAndData": "0x...",
    "signature": "0x..."
  },
  "settlementCallSpec": {
    "merchant":   "0x...",
    "token":      "0x...",
    "amount":     "1000",
    "requestHash":"0x..."
  }
}
```

`userOp` is a full ERC-4337 v0.6 `UserOperation`. `settlementCallSpec` is what the agent claims `userOp.callData` resolves to; the verifier asserts equality.

## `payload` for `exact`

```json
{
  "signature": "0x...",
  "authorization": {
    "from": "0x...",
    "to": "0x...",
    "value": "1000",
    "validAfter": 0,
    "validBefore": 9999999999,
    "nonce": "0x..."
  }
}
```

`signature` is an EIP-712 typed signature over the `authorization` struct. `from` is the EOA that owns the source balance.

## `SettlementResponse` (the receipt)

Success:

```json
{
  "success": true,
  "x402Version": 2,
  "scheme": "aa-native",
  "network": "eip155:1689",
  "transactionHash": "0x...",
  "userOpHash": "0x...",
  "requestHash": "0x...",
  "payer": "0x...",
  "amount": "1000",
  "asset": "0x..."
}
```

Failure:

```json
{
  "success": false,
  "x402Version": 2,
  "errorCode": "user_op_failed",
  "message": "..."
}
```

The full error code list is on the [Errors page](/docs/reference/errors).

## Network identifiers

CAIP-2 strings:

- `eip155:1689` — NERO mainnet
- `eip155:689` — NERO testnet

The `network` field carries the CAIP-2 string in both directions of the wire.

## Encoding

Headers carry **base64url** of the UTF-8 bytes of the canonical JSON. URL-safe alphabet (`-` and `_`); no padding (`=`) on the wire. Implementations decode tolerantly (re-add padding to the next multiple of 4 if needed) but emit canonically (no padding).

```
encoded = base64url_no_pad(utf8(JSON.stringify(value)))
```


---

# SDK overview

> The five @nerochain/x402-* packages — what each one does, and which ones you need.

The NERO 402 SDK is five small packages under the `@nerochain/` scope. Each is independently installable and has a focused responsibility. You only pull in what you use.

## The packages at a glance

| Package | Role | When you need it |
|---|---|---|
| [`@nerochain/x402-types`](/docs/sdk/x402-types) | Wire-format types (Zod + TS) | Always (transitive); install directly only if you write your own adapter. |
| [`@nerochain/x402-server`](/docs/sdk/x402-server) | Merchant middleware (Express, Hono, Fastify, Next, paywall) | You gate an HTTP endpoint behind payment. |
| [`@nerochain/x402-client`](/docs/sdk/x402-client) | Agent HTTP wrapper (fetch, axios) | You make paid calls. |
| [`@nerochain/x402-aa`](/docs/sdk/x402-aa) | Paymaster-sponsored signer | You sign payments from an ERC-4337 SCW. |
| [`@nerochain/x402-extensions`](/docs/sdk/x402-extensions) | Optional protocol extensions (idempotency, signed access tokens) | You want to deduplicate retries or grant cached access after a paid call. |

## What goes together

For an **agent** in the `aa-native` scheme:

```bash
pnpm add @nerochain/x402-client @nerochain/x402-aa ethers
```

For a **merchant** (any framework):

```bash
pnpm add @nerochain/x402-server
```

`@nerochain/x402-types` is a transitive dep of both — there's no need to install it directly unless you're writing a custom adapter, alternative client, or new scheme implementation.

## Design principles

**Wire-format alignment with upstream.** All five packages target `@x402/core@2.11.0`'s envelope shapes. Field names are exactly as upstream specifies. The interop test in `examples/express-paid-api/src/interop.test.ts` round-trips between Coinbase's reference parser and our middleware to catch any divergence.

**No global config.** Every factory takes its config explicitly. There is no module-scope mutable state. Tests can run multiple instances side-by-side; production servers can run multiple merchants in one process with different facilitator URLs.

**Pluggable signers.** `@nerochain/x402-client` is scheme-agnostic. The signer is an interface; `@nerochain/x402-aa` is one implementation. Future schemes (and alternative SCW account contracts) plug in by writing a different signer with the same shape.

**Framework adapters share core logic.** `@nerochain/x402-server` exposes a single `gateRequest` / `settleAfterHandler` core; the Express, Hono, Fastify, and Next adapters are thin wrappers. A handler that works in Express works the same way in Next App Router with no behavioral change.

## What the SDK does not include

- A facilitator implementation. The [reference facilitator](https://github.com/nerochain/nero-x402/tree/main/apps/facilitator) is in the same repo as the SDK but ships separately.
- Direct on-chain calls outside of the UserOp flow. Reading `ReceiptLog` events for independent verification is the consumer's responsibility.
- Wallet connection UI. The SDK takes an already-constructed signer. Use Web3Auth, RainbowKit, ConnectKit, or any other wallet library to obtain the signer.

## Versioning

The packages publish together at the same version. Bumping any one of them bumps all five. Cross-package compatibility is checked in CI; consuming a mix of versions is not supported.


---

# @nerochain/x402-aa

> Paymaster-sponsored signer for the aa-native scheme.

`@nerochain/x402-aa` is the signer that satisfies the `aa-native` scheme. Plug it into `@nerochain/x402-client`'s `x402Fetch` and the agent can pay merchants from an ERC-4337 SCW with sponsored gas.

## Install

```bash
pnpm add @nerochain/x402-aa @nerochain/x402-client ethers
```

## Usage

```ts
import { ethers } from "ethers";
import { x402Fetch } from "@nerochain/x402-client";
import { aaNativeSigner } from "@nerochain/x402-aa";

const wallet = new ethers.Wallet(process.env.NERO_PRIVATE_KEY!);

const f = x402Fetch({
  signer: aaNativeSigner({
    signer: wallet,
    rpcUrl:           "https://rpc.nerochain.io",
    bundlerUrl:       "https://bundler-mainnet.nerochain.io",
    paymasterUrl:     "https://paymaster-mainnet.nerochain.io",
    paymasterApiKey:  process.env.NERO_PAYMASTER_API_KEY!,
    settlementContract: "0x5eCfc64f2339992668f555918674B604F97B412D",
  }),
});
```

## Options

```ts
type AaNativeSignerOptions = {
  signer: ethers.Wallet | ethers.HDNodeWallet;
  rpcUrl: string;
  bundlerUrl: string;
  paymasterUrl: string;
  paymasterApiKey: string;
  settlementContract: string;
  entryPoint?: string;             // default: NERO v0.6 EntryPoint
  accountFactory?: string;          // default: NERO SimpleAccountFactory
  endpointFor?: (req, resource) => string;
  scwSalt?: number | bigint;        // default: 0
};
```

- **`signer`** — the EOA that owns the SCW. Any `ethers.Wallet` or `ethers.HDNodeWallet`. For browser flows, a `JsonRpcSigner` from a Web3Auth provider works in place after a cast (see the [Web3Auth integration guide](/docs/guides/web3auth-integration)).
- **`rpcUrl`** — chain RPC.
- **`bundlerUrl`** — ERC-4337 bundler endpoint.
- **`paymasterUrl`** + **`paymasterApiKey`** — NERO paymaster endpoint and API key. From the [NERO AA Platform dashboard](https://docs.nerochain.io/en/developer-tools/aa-platform).
- **`settlementContract`** — the deployed `SettlementContract` proxy address.
- **`entryPoint`** / **`accountFactory`** — defaults are correct for NERO mainnet and testnet. Override only if you're targeting a different deployment.
- **`endpointFor`** — overrides the canonical endpoint string used in `requestHash`. Default: `resource.url`.
- **`scwSalt`** — distinguish multiple SCWs owned by the same EOA. Default: `0`.

## What the signer does

When `x402Fetch` calls `signer.buildPayload(requirement)`:

1. Compute `requestHash = keccak256(abi.encode(merchant, chainId, "POST", endpoint, timestampBucket, clientNonce))`.
2. Initialize a `SimpleAccount` builder via the [`userop`](https://github.com/nerochain/aa-userop-sdk) SDK using the configured factory and salt.
3. Set paymaster options (type 0) so the bundler routes through the paymaster.
4. Encode `executeBatch([approve(token, settlement, amount), settle(merchant, token, amount, requestHash)])`.
5. Run the paymaster + signature middleware via `Client.buildUserOperation`.
6. Pack the resulting UserOp and the `settlementCallSpec` into the V2 envelope.

The agent's process produces a fully-formed, paymaster-sponsored, signed UserOp ready for the merchant to forward to the facilitator.

## Reading the SCW address

```ts
import { Presets } from "userop";
const builder = await Presets.Builder.SimpleAccount.init(wallet, rpcUrl, {
  overrideBundlerRpc: bundlerUrl,
});
const scwAddress = builder.proxy?.address;
```

The address is deterministic from the EOA and the factory. It's the same on every call; you can compute it ahead of time to fund the SCW (counterfactual) before its first UserOp.

## Errors

If anything in the build / sponsor / sign flow fails (bundler unreachable, paymaster API rejected the key, simulation reverts), the signer throws a `PaymentSignerError` with the underlying cause attached. `x402Fetch` propagates the error to the caller.

```ts
try {
  const res = await f(url, init);
} catch (e) {
  if (e instanceof PaymentSignerError) {
    // failed to construct the payload — bundler / paymaster issue
  } else {
    // network or other error
  }
}
```


---

# @nerochain/x402-client

> A fetch-API-compatible function that auto-handles 402 responses.

`@nerochain/x402-client` is the agent-side package. It returns a `fetch`-compatible function that transparently handles 402 by signing and retrying. The signer is pluggable; the package itself contains no scheme-specific logic.

## Install

```bash
pnpm add @nerochain/x402-client
```

## Usage

```ts
import { x402Fetch, readSettlementReceipt } from "@nerochain/x402-client";
import { aaNativeSigner } from "@nerochain/x402-aa";

const f = x402Fetch({
  signer: aaNativeSigner({ /* ... */ }),
});

const res = await f("https://merchant/api/resource", {
  method: "POST",
  body,
});

const receipt = readSettlementReceipt(res);
```

`f` is a drop-in for the global `fetch`. Anywhere you would call `fetch(...)`, you can call `f(...)`.

## Options

```ts
type X402FetchOptions = {
  signer: PaymentSigner;
  maxRetries?: number;             // default 1
  fetchImpl?: typeof fetch;        // default global fetch
  selectRequirement?: (req: PaymentRequirements) => boolean;
};
```

- **`signer`** — the only required option. See the [`@nerochain/x402-aa`](/docs/sdk/x402-aa) page for the canonical implementation.
- **`maxRetries`** — caps the 402 → retry cycle to prevent infinite loops if a merchant is broken.
- **`fetchImpl`** — override the underlying fetch (useful for tests, custom timeouts, or alternative HTTP clients).
- **`selectRequirement`** — predicate that lets the agent reject specific `accepts[]` entries. Use it to enforce caps ("only pay if amount ≤ X") or merchant allowlists.

## How the retry loop works

```
1. await fetch(input, init)
2. status !== 402?            -> return response
3. no PAYMENT-REQUIRED header? -> return response
4. decode header, find compatible accepts entry
5. await signer.buildPayload(entry, resource)
6. fetch(input, { ...init, headers: { ..., PAYMENT-SIGNATURE: payload } })
7. return response
```

The loop runs at most `maxRetries` times. The default is 1 — exactly one retry per call. If the second response is still 402 (verification failed at the facilitator), `x402Fetch` returns it directly to the caller.

## Reading the settlement receipt

```ts
const receipt = readSettlementReceipt(res);
if (receipt) {
  console.log("settled at:", receipt.transactionHash);
  console.log("amount:    ", receipt.amount);
  console.log("payer:     ", receipt.payer);
}
```

`readSettlementReceipt(response)` extracts and decodes the `PAYMENT-RESPONSE` header. Returns `null` if the header is missing or malformed; callers can treat that case as "the merchant served us without insisting on a receipt".

## Axios integration

For codebases that already use axios, the package exposes an interceptor that retrofits the same 402 → sign → retry behavior onto an existing axios instance. Subpath import:

```ts
import axios from "axios";
import { attachX402 } from "@nerochain/x402-client/axios";
import { aaNativeSigner } from "@nerochain/x402-aa";

const client = axios.create({ baseURL: "https://merchant" });
attachX402(client, { signer: aaNativeSigner({ ... }) });

const res = await client.post("/api/llm", { prompt: "hi" });
```

`attachX402` registers a response interceptor pair (`onFulfilled` + `onRejected`) so it works whether the instance treats 402 as a fulfilled response (`validateStatus: () => true`) or rejects 402 as an error (the axios default). For the success path everywhere, set `validateStatus: (s) => s < 500` on the instance.

`axios` is an optional peer dependency: install it explicitly when you import the subpath.

```bash
pnpm add axios
```

## Implementing a custom signer

A `PaymentSigner` has two methods:

```ts
interface PaymentSigner {
  schemes(): string[];
  buildPayload(
    requirement: PaymentRequirements,
    resource?: ResourceInfo,
  ): Promise<PaymentPayload>;
}
```

`schemes()` advertises which scheme strings this signer can satisfy. `x402Fetch` uses this to filter the merchant's `accepts[]` list before calling `buildPayload`.

`buildPayload` returns the full V2 envelope (`x402Version`, `accepted`, `payload`, `extensions`). The implementation is responsible for the inner `payload` shape, the cryptographic signing, and any external service interactions (paymaster, bundler, etc.).

The reference `aa-native` signer is `@nerochain/x402-aa`'s `aaNativeSigner`. A new scheme would write a parallel signer following the same interface.


---

# @nerochain/x402-extensions

> Optional protocol extensions — payment-identifier (idempotency) and access-token (signed proof-of-payment for cached access).

`@nerochain/x402-extensions` ships optional capabilities that ride on the V2 envelope's `extensions` field or on orthogonal HTTP headers. They are composable with the canonical `@nerochain/x402-server` middleware and `@nerochain/x402-client` signers; nothing in the core wire format changes.

Two extensions are included today.

## Install

```bash
pnpm add @nerochain/x402-extensions
```

## `payment-identifier` — idempotency on retries

A client-supplied identifier carried inside `extensions.paymentIdentifier`. Two requests with the same identifier from the same payer SHOULD result in at most one on-chain settlement; the second response either matches the first (cached) or surfaces a definitive error if the first has not yet completed.

The identifier is opaque to the protocol — any string works. UUIDv4 (or any ≥ 16-byte random value) makes collision negligible.

### Client side

```ts
import {
  generatePaymentIdentifier,
  withPaymentIdentifier,
} from "@nerochain/x402-extensions";

const id = generatePaymentIdentifier();   // crypto.randomUUID() under the hood

// Wrap your signer's payload before sending.
const payload = withPaymentIdentifier(originalPayload, id);
```

Reuse the **same** `id` across retries of the same logical request. A new `id` per logical request, a stable `id` per retry. Persist it in your retry buffer; do not regenerate.

### Server / facilitator side

```ts
import { extractPaymentIdentifier } from "@nerochain/x402-extensions";

const id = extractPaymentIdentifier(payload);
if (id) {
  const cached = await idempotencyStore.get(id);
  if (cached) return cached;             // dedup hit
  // ... process normally, then store the result keyed on `id` ...
}
```

The merchant or facilitator decides where the idempotency store lives. Postgres, Redis, in-memory — any persistence with a `Map<string, Result>` interface works. The identifier travels through the V2 wire format unchanged.

### Relationship to `requestHash`

`requestHash` (defined in the [aa-native scheme](/docs/core-concepts/aa-native-scheme)) is the on-chain replay key, derived deterministically from `(merchant, chainId, method, endpoint, timestampBucket, clientNonce)`. It is the **authoritative** dedup mechanism — the settlement contract rejects duplicate `requestHash` values regardless of any off-chain extension.

`paymentIdentifier` is complementary. It lives at the **HTTP layer**, not the chain layer. It lets a merchant's HTTP layer dedup retries before any chain interaction even happens. Use both: `paymentIdentifier` saves bundler round-trips on duplicates; `requestHash` is the safety net.

## `access-token` — signed proof-of-payment

After a successful settlement, the merchant issues a short-lived signed token from the receipt. The client presents the token on follow-up requests within a TTL to bypass payment for the same resource.

The token rides in a custom header (`X-X402-Access-Token`) so it is orthogonal to the core wire format. The token is HMAC-signed by the merchant: only the merchant can issue or verify; clients treat it as opaque.

### Issuing

```ts
import { issueAccessToken } from "@nerochain/x402-extensions";

// Inside the merchant's settlement-success branch, after readSettlementReceipt(...):
const token = issueAccessToken({
  receipt: {
    payer:           settlement.payer,
    payTo:           settlement.payTo,
    transactionHash: settlement.transactionHash,
  },
  secret:      process.env.MERCHANT_ACCESS_TOKEN_SECRET!,    // ≥ 32 bytes of entropy
  ttlSeconds:  3600,                                          // 1 hour
  scope:       ["GET /api/article/123"],                      // optional
});

res.setHeader("X-X402-Access-Token", token);
res.json({ content: "..." });
```

### Verifying

```ts
import {
  ACCESS_TOKEN_HEADER,
  verifyAccessToken,
} from "@nerochain/x402-extensions";

const tokenHeader = req.headers[ACCESS_TOKEN_HEADER.toLowerCase()];
if (typeof tokenHeader === "string") {
  const result = verifyAccessToken(
    tokenHeader,
    process.env.MERCHANT_ACCESS_TOKEN_SECRET!,
  );
  if (result.valid) {
    // result.claims = { iss, sub, iat, exp, txh, scope? }
    // Skip the payment gate; serve the resource directly.
    return next();
  }
  // result.reason ∈ { "malformed", "signature_mismatch", "expired" }
}
// fall through to normal x402 gate
```

### Security model

- **Secret stays merchant-side.** Only the merchant issues and verifies. A leaked secret means an attacker can mint tokens for any payer; rotate the secret if compromised.
- **Tokens are bound to the original settlement.** `claims.txh` records the on-chain hash that authorized the token; a compliant verifier can additionally check that the transaction is real and matches `claims.sub` (payer) and `claims.iss` (merchant) on chain.
- **TTL bounds blast radius.** Short TTLs (hours, not days) limit the impact of a leaked token.
- **Scope is advisory.** The token's `scope` array is application-level metadata; the merchant's verifier decides how to enforce it.

This is a deliberately minimal mechanism. CAIP-122 / SIWX with full session management is a richer extension worth doing later; for typical "pay once, read for an hour" patterns, signed access tokens are enough.

## Combining the two

A common flow on a paid endpoint with caching:

1. Client sends a request with `X-X402-Access-Token` if it has one.
2. Server verifies the token. On success, serve the response — no payment.
3. On failure (missing/expired/invalid), gate the request as usual: emit 402, accept payment, settle.
4. After settlement, issue a fresh access token. Optionally include a `paymentIdentifier` in the payload to deduplicate retries of the same logical paid request before reaching the bundler.
5. Return the response with both `PAYMENT-RESPONSE` (settlement receipt) and `X-X402-Access-Token` (cached-access grant) headers.

The client's next call lands in step 2 and skips the payment gate until the token expires.


---

# @nerochain/x402-server

> Merchant middleware adapters for Express, Hono, Fastify, and Next.js.

`@nerochain/x402-server` is the merchant-side package. It wraps a normal HTTP handler with the x402 payment gate: 402 on missing payment, forwards the payload to the facilitator on retry, and attaches `PAYMENT-RESPONSE` on the eventual 200.

## Install

```bash
pnpm add @nerochain/x402-server
```

## Adapters

The package exports four adapters via subpath imports — choose the one that matches your framework:

```ts
import { x402Express } from "@nerochain/x402-server/express";
import { x402Hono }    from "@nerochain/x402-server/hono";
import { x402Fastify } from "@nerochain/x402-server/fastify";
import { x402Next }    from "@nerochain/x402-server/next";
```

All four take the same options object.

## Options

```ts
type X402ServerOptions = {
  paymentRequirements: PaymentRequirements | PaymentRequirements[];
  facilitator: { url: string; auth?: string };
  resource?: { url: string; description?: string; mimeType?: string };
  resourceUrl?: string;
  settleBeforeHandler?: boolean;
};
```

- **`paymentRequirements`** — what the merchant accepts. A single entry or an array of entries (multi-scheme or multi-asset).
- **`facilitator.url`** — the facilitator's base URL. The middleware will POST to `{url}/verify` and `{url}/settle`.
- **`facilitator.auth`** — optional bearer token, sent as `Authorization: Bearer <auth>` on facilitator requests.
- **`resource`** — descriptor included in the 402 body. Useful for documentation; not required.
- **`settleBeforeHandler`** — when `true`, the middleware settles before invoking the protected handler. Default `false` (handler runs first, then settle). The default lets the handler skip settlement on cache hits.

## Express example

```ts
import express from "express";
import { x402Express } from "@nerochain/x402-server/express";

const app = express();
app.use(express.json());

app.use(
  "/api/llm",
  x402Express({
    paymentRequirements: {
      scheme: "aa-native",
      network: "eip155:1689",
      amount: "1000",
      asset: USDT,
      payTo: MERCHANT,
      maxTimeoutSeconds: 60,
    },
    facilitator: { url: "https://facilitator.x402.nerochain.io" },
  }),
  (req, res) => {
    res.json({ ok: true, payer: req.x402Payer });
  },
);
```

After successful verification, `req.x402Payer` is populated with the SCW (or EOA, for `exact`) that paid for this request.

## Multi-scheme acceptance

```ts
paymentRequirements: [
  { scheme: "aa-native", network: "eip155:1689", amount: "1000", asset: USDT, payTo, maxTimeoutSeconds: 60 },
  { scheme: "exact",     network: "eip155:1689", amount: "1000", asset: USDT, payTo, maxTimeoutSeconds: 60 },
],
```

The client picks one entry to satisfy. The middleware verifies whichever scheme the client used.

## Paywall (browser-friendly 402 page)

For resources that are paid but also accessible from a browser (a paid article, a gated download), the package exposes a paywall variant that returns a styled HTML page on a 402 challenge when the request's `Accept` header includes `text/html`. Programmatic clients still receive the JSON body; the `PAYMENT-REQUIRED` header is preserved on both branches.

```ts
import express from "express";
import { x402ExpressPaywall } from "@nerochain/x402-server/paywall";

const app = express();
app.use(express.json());

app.use(
  "/api/article/:id",
  x402ExpressPaywall(
    {
      paymentRequirements: { ... },
      facilitator: { url: "https://facilitator.x402.nerochain.io" },
    },
    {
      title: "Pay to read this article",
      brandColor: "#000",
      playgroundUrl: "https://x402.nerochain.io/playground",
    },
  ),
  (req, res) => res.json({ content: "..." }),
);
```

The pure helpers are also exported for users assembling their own adapters:

```ts
import {
  isBrowserRequest,
  renderPaywallHtml,
  paywallizeRejection,
} from "@nerochain/x402-server/paywall";
```

`renderPaywallHtml(paymentRequired, options)` returns the full HTML document; `isBrowserRequest(headers)` is the `Accept`-header detector; `paywallizeRejection(rejection, headers, options)` turns a `GateRejection` into either the JSON or HTML response.

The page is self-contained — inline styles, no external CSS or JS, light + dark mode via `prefers-color-scheme`, and graceful degradation to the JSON 402 for any client without `Accept: text/html`.

## Programmatic core

If you're writing your own framework adapter, `@nerochain/x402-server` exposes the core directly:

```ts
import { gateRequest, settleAfterHandler } from "@nerochain/x402-server";

const gate = await gateRequest({ method, url, headers }, options);
if (gate.kind !== "proceed") return gate;          // 402 or 502 to send back
// run merchant handler...
const settled = await settleAfterHandler(gate, options);
if (settled.kind !== "ok") return settled;          // 502 to send back
// attach PAYMENT-RESPONSE header from settled.paymentResponseHeader, return 200
```

The four adapters are 30-50 line wrappers around this core. You can write a fifth for any framework that exposes a request/response interface.


---

# @nerochain/x402-types

> Wire-format Zod schemas and TypeScript types for x402 V2.

`@nerochain/x402-types` defines the wire format. It exports Zod schemas and TypeScript types that match `@x402/core@2.11.0`. Every other package in the SDK trio depends on it; consumers usually do not install it directly.

## Install

```bash
pnpm add @nerochain/x402-types
```

## What's exported

```ts
import {
  // Outer envelope
  PaymentPayloadSchema,
  PaymentRequiredSchema,
  PaymentRequirementsSchema,
  ResourceInfoSchema,
  SettlementResultSchema,
  SettlementErrorSchema,
  SettlementResponseSchema,

  // Scheme-specific inner payload schemas
  AaNativeInnerPayloadSchema,
  ExactInnerPayloadSchema,

  // HTTP header constants
  HEADER_PAYMENT_REQUIRED,    // "PAYMENT-REQUIRED"
  HEADER_PAYMENT_SIGNATURE,   // "PAYMENT-SIGNATURE"
  HEADER_PAYMENT_RESPONSE,    // "PAYMENT-RESPONSE"

  // Encoding helpers
  encodeHeaderValue,          // unknown -> base64url(JSON)
  decodeHeaderValue,          // base64url(JSON), schema -> T

  // Network helpers
  NeroNetworkSchema,
  NERO_MAINNET_CAIP,          // "eip155:1689"
  NERO_TESTNET_CAIP,          // "eip155:689"
  chainIdOf,                   // (caip) => chainId
} from "@nerochain/x402-types";
```

The TypeScript types are inferred from the schemas: `type PaymentPayload = z.infer<typeof PaymentPayloadSchema>`, and so on for the others.

## Validating a payload at runtime

```ts
import { PaymentPayloadSchema, decodeHeaderValue } from "@nerochain/x402-types";

const headerValue = req.headers["payment-signature"];
const payload = decodeHeaderValue(headerValue, PaymentPayloadSchema);
// payload is fully typed; throws on malformed base64, malformed JSON, or schema mismatch
```

`decodeHeaderValue` is isomorphic — it works in both Node and browsers. It uses `TextEncoder`/`TextDecoder` and `atob`/`btoa` rather than `Buffer`, so client-side bundles don't need a polyfill.

## Header constants vs. literal strings

Always prefer the exported constants over inline strings. The header names are `PAYMENT-REQUIRED`, `PAYMENT-SIGNATURE`, `PAYMENT-RESPONSE` (uppercase with dashes). Consumers reading them off a `Headers` object should try both cases (`HEADER_PAYMENT_RESPONSE` and `HEADER_PAYMENT_RESPONSE.toLowerCase()`); the standard `Headers.get` API is case-insensitive but some intermediaries normalize headers to lowercase.

## Schema versioning

The schemas track `@x402/core@2.11.0` exactly. If upstream bumps the wire format, this package bumps in lockstep. The package exports a constant `X402_VERSION = 2` you can compare against `payload.x402Version` to reject incompatible payloads early.


---

# NERO 402 Glossary

> Ground-truth definitions of NERO 402, x402, and account-abstraction terms for LLMs and agents.

This glossary is the authoritative source for what each technical term means in NERO 402. Machine-readable forms: [https://docs.x402.nerochain.io/glossary.json](https://docs.x402.nerochain.io/glossary.json) (schema.org DefinedTermSet) and the MCP `define_term` tool. Source docs: https://docs.x402.nerochain.io/docs.

## aa-native scheme

The settlement scheme NERO 402 contributes, in which an ERC-4337 smart-contract wallet pays by signing a UserOperation whose callData invokes an on-chain SettlementContract. It works with any standard ERC-20 and is gas-sponsored by a paymaster, so the payer needs no native token.

_Also: aa-native, AA-native._

See: [The aa-native scheme](https://docs.x402.nerochain.io/docs/core-concepts/aa-native-scheme)

## Agent

An autonomous client — a script, LLM agent, or browser tab — that pays for API calls. Integrates with @nerochain/x402-client (the fetch wrapper) and @nerochain/x402-aa (the paymaster-sponsored signer).

See: [Quickstart for agents](https://docs.x402.nerochain.io/docs/getting-started/agents)

## Bundler

An ERC-4337 service that packages UserOperations and submits them to the EntryPoint on chain. NERO 402's facilitator submits aa-native settlements through the NERO bundler.

## CAIP-2 network id

A chain-identifier format used as the network field in x402 payloads, e.g. eip155:1689 for NERO mainnet and eip155:689 for testnet. The wire format treats the network as opaque.

_Also: CAIP-2, network._

See: [Networks](https://docs.x402.nerochain.io/docs/core-concepts/networks)

## DEMO-USDT

A public-mint ERC-20 on NERO testnet (0x9a2eabdecda3eae051bca75fbe71a3dbdb35f9d4) used as a self-faucet settlement asset, so agents can run the full aa-native flow on testnet without real funds.

See: [Networks](https://docs.x402.nerochain.io/docs/core-concepts/networks)

## EIP-3009

An ERC-20 extension (transferWithAuthorization) that lets an EOA authorize a token transfer by signature. The exact scheme depends on it; most tokens such as USDT do not implement it, which is the gap aa-native closes.

_Also: transferWithAuthorization._

## EntryPoint

The singleton ERC-4337 contract that validates and executes UserOperations. NERO uses EntryPoint v0.6 at 0x5FF137D4b0FDCD49DcA30c7CF57E578a026d2789 on both mainnet and testnet.

See: [Networks](https://docs.x402.nerochain.io/docs/core-concepts/networks)

## EOA

Externally Owned Account: a wallet controlled directly by a private key. The exact scheme requires an EOA that can sign EIP-3009; aa-native does not.

_Also: externally owned account._

## ERC-4337

The Ethereum account-abstraction standard that lets smart-contract wallets initiate transactions via UserOperations routed through an EntryPoint and bundler, instead of EOA-signed transactions. NERO Chain runs ERC-4337 v0.6.

_Also: account abstraction, 4337._

See: [Wallet](https://docs.x402.nerochain.io/docs/core-concepts/wallet)

## exact scheme

The upstream x402 settlement scheme in which an EOA signs an EIP-3009 transferWithAuthorization, settled directly against the token contract. Only EOAs and EIP-3009 tokens can use it. NERO 402's facilitator also supports exact for interoperability with unmodified upstream clients.

_Also: exact._

See: [Upstream interop](https://docs.x402.nerochain.io/docs/guides/upstream-interop)

## Facilitator

A service that verifies and settles x402 payments on behalf of merchants. NERO 402's reference facilitator exposes GET /supported, POST /verify, and POST /settle, and speaks both aa-native and exact. Agents never call it directly; merchant middleware does.

See: [Facilitator](https://docs.x402.nerochain.io/docs/core-concepts/facilitator)

## HTTP 402

The HTTP 402 Payment Required status code. x402 uses it to signal that a request must be paid for before the resource is returned, carrying the terms in a PAYMENT-REQUIRED header.

_Also: 402, Payment Required._

See: [HTTP 402](https://docs.x402.nerochain.io/docs/core-concepts/http-402)

## Idempotency (clientNonce)

Deduplication of retried payments via the x402 extensions (e.g. a clientNonce) so a repeated request does not double-settle. Provided by @nerochain/x402-extensions.

_Also: clientNonce._

See: [x402-extensions](https://docs.x402.nerochain.io/docs/sdk/x402-extensions)

## Merchant

The party operating a paid HTTP endpoint that returns 402 to unpaid callers and receives settlement transfers. Integrates with @nerochain/x402-server middleware (Express, Hono, Fastify, Next.js).

See: [Quickstart for merchants](https://docs.x402.nerochain.io/docs/getting-started/merchants)

## Paymaster

An ERC-4337 contract that sponsors gas for a UserOperation so its sender pays no native token. In NERO 402 the paymaster lets an agent's wallet pay APIs while holding only the settlement stablecoin. A NERO Paymaster API key is obtained from the AA Platform dashboard.

See: [Paymaster](https://docs.x402.nerochain.io/docs/core-concepts/paymaster)

## paymasterAndData

The field of an ERC-4337 v0.6 UserOperation that encodes paymaster sponsorship as a single bytes value. v0.7 splits it into separate fields; the NERO SDK targets v0.6, so v0.7-shaped UserOperations are rejected.

## PAYMENT-REQUIRED

The HTTP response header a merchant returns with a 402, carrying base64url-encoded paymentRequirements: scheme, network, amount, asset, and payTo. It is the discovery signal of the x402 flow.

## PAYMENT-RESPONSE

The HTTP response header a merchant returns on success, carrying the settlement receipt including the on-chain transactionHash, payer, amount, and asset.

## PAYMENT-SIGNATURE

The HTTP request header a client sends on retry, carrying the base64url-encoded signed payment payload (for aa-native, the signed UserOperation). It is the credential that authorizes the payment.

See: [Authentication](https://docs.x402.nerochain.io/auth.md)

## Replay protection

Prevention of a payment settling twice. NERO 402 uses an authoritative on-chain isSettled[settlementKey] check keyed by (payer, merchant, token, amount, requestHash), plus an off-chain in-flight registry that rejects duplicates earlier to save a bundler round-trip.

_Also: settlement key, isSettled._

## requestHash

A hash binding a payment to a specific request. It is part of the settlement key used for on-chain replay protection and is echoed back in the settlement receipt.

## Session keys

A pattern that grants an agent a scoped, chain-enforced spending key with caps (per-call and total limits) instead of full wallet authority — the recommended control for serious autonomous-spending deployments.

_Also: session key._

See: [Session keys](https://docs.x402.nerochain.io/docs/advanced/session-keys)

## settlementCallSpec

The object in an aa-native payload declaring merchant, token, amount, and requestHash. The facilitator decodes the signed UserOperation's callData and asserts it resolves to exactly this settle(...) call, preventing a wallet from signing something other than what it claims.

## SettlementContract

The on-chain contract (UUPS-upgradeable, owner-allowlisted, replay-protected) that executes aa-native settlements. settle(merchant, token, amount, requestHash) runs IERC20.transferFrom from the payer's wallet to the merchant and records the settlement key.

_Also: settlement contract._

See: [Settlement contract](https://docs.x402.nerochain.io/docs/core-concepts/settlement-contract)

## SimpleAccount / SimpleAccountFactory

The canonical ERC-4337 account contract and its deterministic factory used to derive an agent's smart-contract-wallet address from its signing key. The address is known before deployment; the wallet deploys itself on its first sponsored UserOperation.

_Also: SimpleAccount, SimpleAccountFactory._

## Smart-contract wallet (SCW)

A wallet implemented as a smart contract (an ERC-4337 account) rather than a key-controlled EOA. On NERO Chain every wallet is an SCW, which is why the EOA-only exact scheme is unusable there and aa-native exists.

_Also: SCW, smart account._

See: [Wallet](https://docs.x402.nerochain.io/docs/core-concepts/wallet)

## Type-0 paymaster sponsorship

NERO's full-sponsorship paymaster mode in which the agent's wallet spends zero native gas on a paid call, including its own first-time deployment.

_Also: type 0._

See: [Paymaster](https://docs.x402.nerochain.io/docs/core-concepts/paymaster)

## UserOperation

The ERC-4337 pseudo-transaction object a smart-contract wallet signs. In aa-native, its callData decodes to SettlementContract.settle(...), and the facilitator asserts that decoding matches the declared settlementCallSpec before submitting it.

_Also: UserOp._

See: [The aa-native scheme](https://docs.x402.nerochain.io/docs/core-concepts/aa-native-scheme)

## Wire format (envelope)

The canonical x402 V2 payload shape: x402Version, accepted (the requirements), payload (scheme-specific inner data), and extensions. NERO 402 keeps it identical to upstream; only the inner payload differs by scheme.

_Also: envelope._

See: [Wire format](https://docs.x402.nerochain.io/docs/reference/wire-format)

## x402

An HTTP-native payment protocol built on the 402 Payment Required status code. A server answers 402 with payment terms; the client pays and retries with a signed payment payload; the server returns the content plus a receipt. NERO 402 implements x402 V2.

See: [HTTP 402](https://docs.x402.nerochain.io/docs/core-concepts/http-402)

## x402 V2

Version 2 of the x402 protocol and its wire envelope (@x402/core@2.11.0). NERO 402 uses the canonical V2 envelope unchanged; only the inner payload differs per scheme, so upstream V2 clients interoperate.

_Also: x402Version 2, @x402/core._

See: [Wire format](https://docs.x402.nerochain.io/docs/reference/wire-format)


---

## Constraints and limitations

- The on-chain `SettlementContract` is **not yet audited**; v1.0 of the SDK waits on a clean external audit. Do not route significant production value through the pre-audit contract.
- Targets **ERC-4337 v0.6** (NERO Chain's bundler version). v0.7-shaped UserOperations are rejected.
- **No refunds** in v1 — a successful settlement is final. Refund logic lives at the application layer.
- **One payment per HTTP request.** Paying multiple merchants means multiple requests.
- `aa-native` settlement currently requires the **NERO 402 facilitator**; the scheme is on a path to upstream standardization (`coinbase/x402#639`).

## Links

- Whitepaper: https://docs.x402.nerochain.io/whitepaper.pdf
- Source: https://github.com/nerochain/nero-x402
- Contact: help-support@nerochain.io
