<!-- Generated raw Markdown for /reference/typescript; product pin 638fa1e9ca7face19a442cef43754f0d627c7705. -->

Two SubEtha packages are published to npm; both are Apache-2.0, ESM-only, and
require Node.js >= 20. Everything below is the surface actually exported by
the package entry points at the pinned product commit — nothing more.

<VersionBadge name="@subetha/x402-scheme" version="0.1.0" registry="npm" verified="2026-07-27" />
<VersionBadge name="@subetha/provider" version="0.1.0" registry="npm" verified="2026-07-27" />

The facilitator is **not** on this list on purpose: `@subetha/facilitator` is
private/workspace-internal and is operated from the product repository source
only (npm returns 404 for it — see
[Versions & compatibility](/reference/compatibility/)).

## `@subetha/x402-scheme` — payer-side scheme, types, fees

```bash
npm install @subetha/x402-scheme @x402/core
```

`@x402/core` (`^2.17.0`) is a peer dependency; `viem` (`^2.21.0`) is installed
automatically as a regular dependency. The package entry re-exports three
modules
([`src/index.ts`](https://github.com/peaceandwhisky/SubEtha/blob/638fa1e9ca7face19a442cef43754f0d627c7705/packages/x402-scheme/src/index.ts)):

### Constants and network helpers ([`types.ts`](https://github.com/peaceandwhisky/SubEtha/blob/638fa1e9ca7face19a442cef43754f0d627c7705/packages/x402-scheme/src/types.ts))

| export | kind | description |
|---|---|---|
| `SUBETHA_SCHEME` | `const` | the scheme identifier, `"subetha-zerc20"` |
| `DEFAULT_EXPIRY_SKEW_SECONDS` | `const` | clock-skew margin (5): clients treat `expiresAt <= now + skew` as expired |
| `DEFAULT_LAST_BROADCAST_CUTOFF_SECONDS` | `const` | self-transfer safety margin (30): refuse to broadcast a burn this close to expiry |
| `MAX_REASONABLE_EPOCH_SECONDS` | `const` | `1e11` — values at/above this cannot be unix seconds (milliseconds guard) |
| `toNetwork(chainId)` | function | CAIP-2 id for an EVM chain id (`eip155:<chainId>`) |
| `parseNetwork(network)` | function | parse a CAIP-2 `eip155` id back to a chain id; throws on non-eip155 input |

### Wire types and validation ([`types.ts`](https://github.com/peaceandwhisky/SubEtha/blob/638fa1e9ca7face19a442cef43754f0d627c7705/packages/x402-scheme/src/types.ts))

| export | kind | description |
|---|---|---|
| `SubethaFeeInfo` | interface | fee disclosure `{ amount, bps }` (payer-charged mode only; already included in `amount`) |
| `SubethaExtra` | interface | the scheme's `PaymentRequirements.extra`: `challengeNonce`, `expiresAt`, `helper?`, `deadline?`, `fee?` |
| `SubethaPermitPayload` | interface | gasless payload: `challengeNonce`, `payer`, `permit { value, nonce, deadline, v, r, s }`, `burnAuthSig` |
| `SubethaSelfTransferPayload` | interface | fallback payload: `challengeNonce`, `burnTxHash` |
| `parseSubethaRequirements(requirements)` | function | validate + narrow an offer's SubEtha fields (`payTo`, `asset`, `amount`, `chainId`, `extra`); throws a specific message on anything malformed |

### Payer client ([`client.ts`](https://github.com/peaceandwhisky/SubEtha/blob/638fa1e9ca7face19a442cef43754f0d627c7705/packages/x402-scheme/src/client.ts))

| export | kind | description |
|---|---|---|
| `SubethaSchemeClientOptions` | interface | `account` (required), `mode?` (`"permit"` default \| `"self-transfer"`), `rpcUrl?`, `publicClient?`, `walletClient?`, `expirySkewSeconds?`, `lastBroadcastCutoffSeconds?` |
| `SubethaSchemeClient` | class | x402 v2 scheme handler for `subetha-zerc20` (structurally implements the official `SchemeNetworkClient`). Members: `scheme`, `createPaymentPayload(x402Version, requirements)`, `burnTxFor(challengeNonce)` (self-transfer mode), `lastRequirements` |

In the default `"permit"` mode the client fail-fasts when an offer lacks
`extra.helper` — it never silently degrades to a gas-paying transfer.
Construction requires `rpcUrl` or an injected `publicClient`.

### Fee interpretation ([`fee.ts`](https://github.com/peaceandwhisky/SubEtha/blob/638fa1e9ca7face19a442cef43754f0d627c7705/packages/x402-scheme/src/fee.ts))

| export | kind | description |
|---|---|---|
| `ParsedFee` | interface | `{ fee, bps, quoted, listPrice }` (all amounts as `bigint` base units) |
| `parseFee(requirements)` | function | typed view of an offer's fee disclosure; `undefined` when the offer carries no fee field |
| `feeAwarePolicy()` | function | a `PaymentPolicy` for the official x402 client that ranks offers by the **quoted** total (the payer's true spend), never by list price |

### Payer wiring (from the protocol spec)

```ts
const scheme = new SubethaSchemeClient({ account, mode: "permit", rpcUrl });
const client = new x402Client().register("eip155:31337", scheme);
const fetchWithPay = wrapFetchWithPayment(fetch, client);
```

## `@subetha/provider` — provider-side scheme server and handler

```bash
npm install @subetha/provider @x402/core
```

`@x402/core` (`^2.17.0`) is a peer dependency; `@subetha/x402-scheme` is
installed automatically as a regular dependency. The package entry re-exports
four modules
([`src/index.ts`](https://github.com/peaceandwhisky/SubEtha/blob/638fa1e9ca7face19a442cef43754f0d627c7705/packages/provider/src/index.ts)):

### Facilitator HTTP client ([`facilitator-client.ts`](https://github.com/peaceandwhisky/SubEtha/blob/638fa1e9ca7face19a442cef43754f0d627c7705/packages/provider/src/facilitator-client.ts))

| export | kind | description |
|---|---|---|
| `SubethaChallengeOffer` | interface | the facilitator's `/challenge` response: `payTo`, `amount`, `token`, `chainId`, `challengeNonce`, `expiresAt`, `helper?`, `deadline?`, `fee?` |
| `SubethaFacilitatorClient` | class | implements the official `FacilitatorClient` over HTTP: `verify(…)`, `settle(…)`, `getSupported()`, plus the SubEtha extension `createChallenge(priceBaseUnits)` |

The facilitator is reached as an **external HTTP service** — this package
includes no facilitator runtime or backend and does not enable launching one.

### Payment handler ([`handler.ts`](https://github.com/peaceandwhisky/SubEtha/blob/638fa1e9ca7face19a442cef43754f0d627c7705/packages/provider/src/handler.ts))

| export | kind | description |
|---|---|---|
| `HandlerResult` | interface | what a resource handler returns instead of writing to `res`: `{ body, status?, contentType? }` |
| `SubethaHandlerResponse` | interface | the structural slice of `express.Response` the wrapper drives (no express dependency) |
| `subethaHandler(fn)` | function | wraps a return-value handler into an Express-compatible route handler with exactly one response commit; a thrown handler becomes a 500 and the payment is **not** settled |

### Scheme server ([`scheme-server.ts`](https://github.com/peaceandwhisky/SubEtha/blob/638fa1e9ca7face19a442cef43754f0d627c7705/packages/provider/src/scheme-server.ts))

| export | kind | description |
|---|---|---|
| `SUBETHA_PLACEHOLDER_PAYTO` | `const` | fallback `payTo` for **static quote-only** route configs; real payment routes must use `subethaAccepts` |
| `SubethaSchemeServerOptions` | interface | `maxCachedOffers?` (default 5000), `clock?`, `feePolicy?` |
| `SubethaSchemeServer` | class | structurally implements the official `SchemeNetworkServer`; mints one fresh burn-address offer per unpaid 402 via the facilitator and caches live offers in memory (single-process assumption) |
| `subethaAccepts(schemeServer, { network, price })` | function | builds a route's `accepts` entry whose dynamic `payTo` mints per 402 and echoes the client's `accepted.payTo` on the paying request |

### Offer validation ([`validate.ts`](https://github.com/peaceandwhisky/SubEtha/blob/638fa1e9ca7face19a442cef43754f0d627c7705/packages/provider/src/validate.ts))

| export | kind | description |
|---|---|---|
| `EXPIRY_SKEW_SECONDS` | `const` | re-export of the shared clock-skew margin |
| `OfferBinding` | interface | the identity an offer is bound to |
| `SubethaFeePolicy` | interface | the facilitator's non-secret fee policy as the provider expects it |
| `validateFeePolicy(policy)` | function | fail-fast structural validation of a fee policy |
| `SubethaOfferEntry` | interface | a fully-built cached offer entry |
| `canonicalizePathname(path)` | function | path canonicalization for offer binding |
| `bindingsEqual(a, b)` | function | offer-binding equality |
| `validateChallengeOffer(…)` | function | validates a facilitator challenge offer against the expected binding and fee policy |
| `validateBuiltRequirements(…)` | function | validates the requirements object built from an offer |

### Provider wiring (from the protocol spec)

```ts
const facilitator = new SubethaFacilitatorClient(FACILITATOR_URL);
const scheme = new SubethaSchemeServer(facilitator);
const server = new x402ResourceServer([facilitator]);
server.register("eip155:31337", scheme);
await server.initialize(); // hard-fails unless /supported advertises the kind
app.use(paymentMiddleware({ "/api/*": {
  accepts: subethaAccepts(scheme, { network: "eip155:31337", price: "1000" }),
} }, server));
```

`price` is the **list price** in base units; the quoted `amount` (with any
fee) comes from the facilitator per request. The provider holds no keys except
its payout EOA and never touches the chain or the zERC20 SDK.

## Related pages

- [Wire protocol reference](/reference/protocol/) — the formats these APIs
  produce and consume.
- [Configuration reference](/reference/configuration/) — the `SUBETHA_*`
  payer environment.
- [Python API](/reference/python/) — the PyPI payer package.
