TransX402 Docs
Integrations

JavaScript Library

Complete guide to @transx402/client — subpath imports, createBrowserClient, createPaywall, agents, and settlement modes for IDRX x402.

Overview

@transx402/client is a browser and Node.js library for IDRX x402 payments. Import clients from subpaths — the package root exports types and errors only.

For full-stack integrations (recommended), pair it with @transx402/server: the client signs; your backend calls POST /facilitate.

Settlement modeWho calls /facilitateDefault forAPI key
server (canonical)Merchant backend (@transx402/server)fetch()Server env only — omit in the browser
directBrowser / agentpay() / createPaywall()Publishable ipk_pub_sandbox_ / ipk_pub_live_ (register Allowed Origins first)

Installation

npm install @transx402/client
# Canonical full-stack settlement:
npm install @transx402/server

Requires Node.js 20.19+. For zero-build HTML, see CDN Usage. WordPress sites should use the WordPress Plugin, not this npm package, in the browser.

Import pathRole
@transx402/clientTypes, FacilitationError, helpers — no createBrowserClient
@transx402/client/browserPath 4: createBrowserClient, createPaywall, CDN TransX402
@transx402/client/agentPath 3: createAgentClient (Node, private key)
import type { PaymentResult, SettlementMode } from "@transx402/client";
import { FacilitationError, formatFacilitationError } from "@transx402/client";
import { createBrowserClient, createPaywall } from "@transx402/client/browser";
import { createAgentClient } from "@transx402/client/agent";

Canonical: createBrowserClient + fetch()

import { createBrowserClient } from "@transx402/client/browser";
 
const client = createBrowserClient({
  environment: "camp", // "local" | "camp" | "base"
  settlement: "server", // default for fetch()
  configProxyPath: "/api/transx402", // → GET /api/transx402/config
});
 
const response = await client.fetch("/api/premium");

TypeScript forbids apiKey when environment is set and settlement is "server". Wire the proxy with tx402.config.handleRequest.

You may set facilitatorUrl to override the preset host; the config section still follows environment. Chain / RPC / IDRX / Permit2 come only from GET /config.

client.fetch(url, init?)

Drop-in replacement for fetch(). Automatically handles 402 responses.

Internal flow (settlement: "server", default):

  1. Sends a normal fetch() request
  2. If response is 402, parses payment requirements
  3. Connects wallet (if not connected)
  4. Signs x402 payment payload (Exact EVM + Permit2 witness)
  5. Retries the original request with PAYMENT-SIGNATURE / X-PAYMENT
  6. Your merchant API settles via @transx402/server → POST /facilitate
  7. Returns the final response

Internal flow (settlement: "direct"): steps 1–4, then the client calls POST /facilitate itself before the retry. Used by pay() and the paywall.

Direct settlement: pay()

Zero-backend payments. Requires a publishable API key.

const direct = createBrowserClient({
  apiKey: "ipk_pub_sandbox_...",
  environment: "camp",
  settlement: "direct",
});
 
const result = await direct.pay({
  to: "0xMerchantWallet",
  amount: "5000", // whole IDR; library ×100 → IDRX base units
  currency: "IDR",
  resource: "https://example.com/article/123",
});
 
console.log("Payment successful:", result.txHash);

Paywall: createPaywall()

Imperative overlay — not a React component. Always uses direct settlement.

import { createPaywall } from "@transx402/client/browser";
 
createPaywall({
  apiKey: "ipk_pub_sandbox_...",
  environment: "camp",
  selector: "#premium-content",
  price: 5000,
  currency: "IDR",
  merchantWallet: "0xMerchant...",
  title: "Premium Article",
  description: "Pay Rp 5,000 to read this article",
});

CDN equivalent: TransX402.paywall({ ... }) from the browser bundle.

The overlay includes price in IDR, Pay with IDRX, wallet connect, Permit2 approve, signature, and a transaction link.

Theme

createPaywall({
  apiKey: "ipk_pub_sandbox_...",
  environment: "camp",
  selector: "#premium-content",
  price: 5000,
  merchantWallet: "0xMerchant...",
  theme: {
    primary: "#2563eb",
    background: "#ffffff",
    text: "#0f172a",
    borderRadius: "12px",
  },
});

Agent: createAgentClient

Path 3 — Node private key. Sponsored Permit2 approve via signTransaction. Do not use this in MetaMask (browsers cannot eth_signTransaction).

import { createAgentClient } from "@transx402/client/agent";
 
const agent = createAgentClient({
  environment: "camp",
  privateKey: "0x...",
  settlement: "server", // merchant API must call @transx402/server
  configProxyPath: "http://localhost:3420/api/transx402", // absolute URL in Node
});
 
await agent.fetch("http://localhost:3420/api/premium");
console.log("Agent address:", agent.address);

For settlement: "direct", pass a publishable apiKey. Relative configProxyPath works in the browser only.

Other browser methods

const address = await client.connectWallet(); // EIP-1193 / window.ethereum
await client.isWalletConnected();
await client.getNetworkConfig(); // from GET /config (or proxy)
 
const { approved, allowance } = await client.checkApproval();
if (!approved) {
  await client.requestApproval(); // usually handled automatically
}

Configuration options

OptionTypeNotes
environment"local" | "camp" | "base"Selects config section + preset host
facilitatorUrlstringOptional host override; section still follows environment
configProxyPathstringSame-origin proxy base for GET …/config (server settlement). Default /api/transx402
settlement"server" | "direct"Default "server" for fetch()
apiKeystringRequired for direct / pay() / paywall; omitted for server fetch()
onPaymentStartfunctionPayment started
onPaymentSuccessfunctionPayment succeeded
onPaymentErrorfunctionPayment failed
onWalletConnectfunctionWallet connected
onApprovalRequiredfunctionOptional manual requestApproval() hook

Do not pass token or network — those are not client options. Config comes from GET /config.

Errors

import { FacilitationError, formatFacilitationError } from "@transx402/client";
 
try {
  await client.fetch("/api/premium");
} catch (error) {
  if (error instanceof FacilitationError) {
    console.error(error.code, formatFacilitationError(error));
    // insufficient_balance, no_permit2_approval, ...
  }
}

Also: WalletConnectionError, Permit2Error. After server settlement, a failed gate may return HTTP 402/500 with { code, error, details } — rehydrate FacilitationError from the body if you need the same UX.

Compatibility

Browser

  • Chrome 90+, Firefox 90+, Safari 15+, Edge 90+
  • Mobile: Chrome Android, Safari iOS
  • Wallet: MetaMask / EIP-1193 (window.ethereum) only

Node.js

  • Node.js 20.19+ (built-in fetch)
  • Agents: @transx402/client/agent with a private key

Full example (server settlement)

import { FacilitationError, formatFacilitationError } from "@transx402/client";
import { createBrowserClient } from "@transx402/client/browser";
 
const client = createBrowserClient({
  environment: "camp",
  settlement: "server",
  configProxyPath: "/api/transx402",
  onPaymentError: (error) => {
    if (error instanceof FacilitationError && error.code === "insufficient_balance") {
      alert("Your IDRX balance is insufficient");
    }
  },
});
 
try {
  const response = await client.fetch("/api/premium");
  const data = await response.json();
  renderContent(data);
} catch (error) {
  console.error("Failed to fetch content:", formatFacilitationError(error as FacilitationError));
}

On this page