SDKsTypeScriptOverview

TypeScript SDK

The T402 TypeScript SDK provides comprehensive support for HTTP-native stablecoin payments across 11 blockchain families.

v2.8.0 Released - 39 packages under @t402 on npm, with Stellar support, ERC-8004 Trustless Agents and expanded multi-chain support.

Core Packages

PackageVersionDescription
@t402/core2.8.0Protocol types and HTTP utilities
@t402/extensions2.8.0Protocol extensions and helpers

Blockchain Mechanisms

PackageVersionDescription
@t402/evm2.8.0EVM chains (Ethereum, Arbitrum, Base, etc.) with EIP-3009
@t402/evm-core2.8.0EVM types and utilities without viem dependency
@t402/svm2.8.0Solana blockchain with SPL token transfers
@t402/ton2.8.0TON blockchain with USDT Jetton support
@t402/tron2.8.0TRON blockchain with TRC-20 USDT
@t402/near2.8.0NEAR Protocol with NEP-141 USDT
@t402/aptos2.8.0Aptos blockchain with Fungible Asset USDT
@t402/tezos2.8.0Tezos blockchain with FA2 USDt
@t402/polkadot2.8.0Polkadot Asset Hub with USDT
@t402/stacks2.8.0Stacks (Bitcoin L2) with SIP-010 USDT
@t402/cosmos2.8.0Cosmos (Noble) with bank MsgSend
@t402/btc2.8.0Bitcoin with Lightning Network
@t402/stellar2.8.0Stellar blockchain with Soroban SEP-41 USDC
@t402/erc80042.8.0ERC-8004 Trustless Agents identity and reputation

Bundle Size Optimization: Use @t402/evm-core instead of @t402/evm if you only need types and don’t require viem. This significantly reduces bundle size for type-only consumers.

WDK Integration (Tether Wallet Development Kit)

PackageVersionDescription
@t402/wdk2.8.0Tether WDK integration for EVM, TON, Solana, TRON
@t402/wdk-protocol2.8.0T402 payment protocol for WDK wallet apps
@t402/wdk-gasless2.8.0Gasless payments via ERC-4337 account abstraction
@t402/wdk-bridge2.8.0Cross-chain bridging via LayerZero OFT
@t402/wdk-multisig2.8.0Safe multi-signature wallet support

HTTP Server Frameworks

FrameworkPackageVersion
Express.js@t402/express2.8.0
Next.js@t402/next2.8.0
Hono@t402/hono2.8.0
Fastify@t402/fastify2.8.0

HTTP Client Libraries

ClientPackageVersion
Fetch API@t402/fetch2.8.0
Axios@t402/axios2.8.0

UI Components

PackageVersionDescription
@t402/paywall2.8.0Universal paywall component (framework-agnostic)
@t402/react2.8.0React hooks and components
@t402/vue2.8.0Vue 3 composables and components

Tools

PackageVersionDescription
@t402/cli2.8.0Command-line tools for testing and development
@t402/mcp2.8.0MCP server for AI agent payments (14 tools: 6 base + 5 WDK + 3 ERC-8004)

Package Structure

Quick Install

# Core + EVM (most common)
pnpm add @t402/core @t402/evm
 
# With Express middleware
pnpm add @t402/core @t402/evm @t402/express
 
# Full client setup with fetch wrapper
pnpm add @t402/core @t402/evm @t402/fetch
 
# Multi-chain support (all 10 blockchain families)
pnpm add @t402/core @t402/evm @t402/svm @t402/ton @t402/tron @t402/near @t402/aptos @t402/tezos @t402/polkadot @t402/stacks

Architecture

@t402/core                  Base types, HTTP utilities

    ├── @t402/evm-core      EVM types and constants (no viem dependency)
    │       │
    │       └── @t402/evm   EVM mechanism (EIP-3009, ERC-4337, LayerZero)

    ├── @t402/svm           Solana mechanism (SPL tokens)

    ├── @t402/ton           TON mechanism (Jettons)

    ├── @t402/tron          TRON mechanism (TRC-20)

    ├── @t402/near          NEAR mechanism (NEP-141)

    ├── @t402/aptos         Aptos mechanism (Fungible Asset)

    ├── @t402/tezos         Tezos mechanism (FA2)

    ├── @t402/polkadot      Polkadot mechanism (Asset Hub)

    ├── @t402/stacks        Stacks mechanism (SIP-010)

    └── @t402/wdk           Tether WDK integration (EVM, TON, Solana, TRON)

        ├── @t402/wdk-protocol  T402 payment protocol for WDK apps

        ├── @t402/wdk-gasless   ERC-4337 gasless payments

        ├── @t402/wdk-bridge    LayerZero cross-chain bridge

        └── @t402/wdk-multisig  Safe multi-sig wallets

Quick Start

Client (Make Payments)

import { t402Client, wrapFetchWithPayment } from "@t402/fetch";
import { registerExactEvmScheme } from "@t402/evm/exact/client";
import { privateKeyToAccount } from "viem/accounts";
 
// Create t402 client
const client = new t402Client();
 
// Register EVM payment mechanism
registerExactEvmScheme(client, {
  signer: privateKeyToAccount(process.env.PRIVATE_KEY as `0x${string}`),
});
 
// Wrap fetch for automatic payment handling
const fetchWithPayment = wrapFetchWithPayment(fetch, client);
 
// Make request - 402 payments handled automatically
const response = await fetchWithPayment("https://api.example.com/data");
const data = await response.json();

Server (Require Payments)

import express from "express";
import { paymentMiddleware, t402ResourceServer } from "@t402/express";
import { ExactEvmScheme } from "@t402/evm/exact/server";
 
const app = express();
 
// Configure payment routes
app.use(
  paymentMiddleware(
    {
      "GET /api/data": {
        accepts: [
          {
            scheme: "exact",
            price: "$0.01",
            network: "eip155:8453",
            payTo: "0xYourAddress",
          },
        ],
        description: "Premium API data",
        mimeType: "application/json",
      },
    },
    new t402ResourceServer(facilitatorClient)
      .register("eip155:8453", new ExactEvmScheme()),
  ),
);
 
// Protected endpoint
app.get("/api/data", (req, res) => {
  res.json({ message: "Premium content!" });
});
 
app.listen(3000);

Gasless Payments (ERC-4337)

Enable gasless payments using account abstraction:

import {
  SafeSmartAccount,
  createBundlerClient,
  createPaymaster,
} from "@t402/evm/erc4337";
import { privateKeyToAccount } from "viem/accounts";
 
// Create Safe smart account
const safeAccount = new SafeSmartAccount({
  owner: privateKeyToAccount(ownerPrivateKey),
  chainId: 8453, // Base
});
 
// Create bundler and paymaster clients
const bundler = createBundlerClient({
  provider: "pimlico",
  apiKey: process.env.PIMLICO_API_KEY,
  chainId: 8453,
});
 
const paymaster = createPaymaster({
  provider: "pimlico",
  apiKey: process.env.PIMLICO_API_KEY,
  chainId: 8453,
});
 
// Build and send UserOperation
const callData = safeAccount.encodeExecute(targetAddress, 0n, data);
const userOp = await bundler.buildUserOperation({
  sender: smartAccountAddress,
  callData,
});
 
// Sponsor with paymaster
const sponsoredOp = await paymaster.sponsor(userOp);
 
// Send UserOperation
const hash = await bundler.sendUserOperation({
  ...sponsoredOp,
  signature: await safeAccount.signUserOp(sponsoredOp),
});
 
// Wait for receipt
const receipt = await bundler.waitForReceipt(hash);

Cross-Chain Bridge (USDT0)

Bridge USDT0 between chains using LayerZero:

import { Usdt0Bridge, LayerZeroScanClient } from "@t402/evm";
 
// Create bridge client
const bridge = new Usdt0Bridge(signer, "arbitrum");
 
// Get quote
const quote = await bridge.quote({
  fromChain: "arbitrum",
  toChain: "ethereum",
  amount: 100_000000n, // 100 USDT0
  recipient: "0xRecipientAddress",
});
 
console.log(`Fee: ${quote.nativeFee}`);
 
// Execute bridge
const result = await bridge.send({ ...quote });
console.log(`Message GUID: ${result.messageGuid}`);
 
// Track status
const scanClient = new LayerZeroScanClient();
await scanClient.waitForDelivery(result.messageGuid);
console.log("Bridge complete!");

MCP Server (AI Agents)

Run an MCP server for AI agent payments. With a WDK seed phrase, agents get 11 tools including wallet operations, token transfers, swaps, and auto-pay:

# Install and run MCP server (6 base tools)
npx @t402/mcp
 
# With WDK wallet tools (11 tools)
T402_WDK_SEED_PHRASE="your seed phrase" npx @t402/mcp

Configure in Claude Desktop:

{
  "mcpServers": {
    "t402": {
      "command": "npx",
      "args": ["@t402/mcp"],
      "env": {
        "T402_DEMO_MODE": "true",
        "T402_WDK_SEED_PHRASE": "abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about"
      }
    }
  }
}

Available tools: t402/verify, t402/settle, t402/supported, t402/getRequirements, t402/getAllBalances, t402/pay + WDK tools: wdk/getWallet, wdk/getBalances, wdk/transfer, wdk/swap, t402/autoPay

See MCP Integration for full documentation.

Framework Integration Patterns

Next.js App Router

// app/api/premium/route.ts
import { withT402 } from "@t402/next";
 
export const GET = withT402(
  async (req) => {
    return Response.json({ data: "Premium content!" });
  },
  {
    accepts: [
      { scheme: "exact", price: "$0.01", network: "eip155:8453", payTo: "0x..." },
    ],
    description: "Premium API endpoint",
  }
);

Hono

import { Hono } from "hono";
import { paymentMiddleware } from "@t402/hono";
 
const app = new Hono();
 
app.use(
  "/api/*",
  paymentMiddleware({
    "GET /api/data": {
      accepts: [{ scheme: "exact", price: "$0.01", network: "eip155:8453", payTo: "0x..." }],
    },
  })
);
 
app.get("/api/data", (c) => c.json({ data: "Premium!" }));

Fastify

import Fastify from "fastify";
import { t402Plugin } from "@t402/fastify";
 
const app = Fastify();
 
app.register(t402Plugin, {
  routes: {
    "GET /api/data": {
      accepts: [{ scheme: "exact", price: "$0.01", network: "eip155:8453", payTo: "0x..." }],
    },
  },
});
 
app.get("/api/data", async () => ({ data: "Premium!" }));

Axios Client

import axios from "axios";
import { wrapAxiosWithPayment } from "@t402/axios";
import { registerExactEvmScheme } from "@t402/evm/exact/client";
 
const client = new t402Client();
registerExactEvmScheme(client, { signer });
 
const api = wrapAxiosWithPayment(axios.create(), client);
 
const response = await api.get("https://api.example.com/data");

Lifecycle Hooks

Client Hooks

import { t402Client } from "@t402/core";
 
const client = new t402Client();
 
// Before payment creation
client.onBeforePaymentCreation((ctx) => {
  console.log(`Creating payment for ${ctx.requirements.network}`);
 
  // Abort if price too high
  if (BigInt(ctx.requirements.maxAmountRequired) > MAX_PRICE) {
    return { abort: true, reason: "Price exceeds limit" };
  }
});
 
// After successful payment
client.onAfterPaymentCreation((ctx) => {
  metrics.increment("payments.created", {
    network: ctx.requirements.network,
    scheme: ctx.requirements.scheme,
  });
});
 
// On payment failure
client.onPaymentCreationFailure((ctx) => {
  logger.error("Payment failed", { error: ctx.error });
});

Server Hooks

import { t402ResourceServer } from "@t402/core";
 
const server = new t402ResourceServer(facilitator);
 
// Before verification
server.onBeforeVerify((ctx) => {
  if (isBlacklisted(ctx.payload.authorization.from)) {
    return { abort: true, reason: "Payer is blocked" };
  }
});
 
// After successful settlement
server.onAfterSettle((ctx) => {
  db.recordPayment({
    txHash: ctx.result.transaction,
    payer: ctx.result.payer,
    amount: ctx.requirements.maxAmountRequired,
  });
});

Error Handling

Client-Side Errors

import { t402Client, PaymentError, PaymentAbortedError } from "@t402/core";
 
try {
  const response = await fetchWithPayment("https://api.example.com/data");
} catch (error) {
  if (error instanceof PaymentAbortedError) {
    // Payment was aborted by a hook
    console.log("Payment aborted:", error.reason);
  } else if (error instanceof PaymentError) {
    // Payment creation failed
    console.log("Payment failed:", error.message);
  } else {
    // Network or other error
    throw error;
  }
}

Server-Side Errors

import { paymentMiddleware } from "@t402/express";
 
app.use(
  paymentMiddleware(routes, server, {
    onError: (error, req, res) => {
      logger.error("Payment error", { error, path: req.path });
      res.status(500).json({ error: "Payment processing failed" });
    },
    onSettlement: (result, req) => {
      logger.info("Payment settled", {
        txHash: result.transaction,
        payer: result.payer,
      });
    },
  })
);

Dynamic Pricing

Per-Request Pricing

app.use(
  paymentMiddleware({
    "GET /api/data": {
      accepts: [
        {
          scheme: "exact",
          network: "eip155:8453",
          payTo: "0x...",
          // Dynamic price based on request
          price: (req) => {
            const tier = getUserTier(req);
            return tier === "premium" ? "$0.001" : "$0.01";
          },
        },
      ],
    },
  })
);

Dynamic PayTo Address

app.use(
  paymentMiddleware({
    "GET /api/marketplace/:id": {
      accepts: [
        {
          scheme: "exact",
          network: "eip155:8453",
          price: "$10.00",
          // Route payment to seller
          payTo: async (req) => {
            const item = await db.getItem(req.params.id);
            return item.sellerAddress;
          },
        },
      ],
    },
  })
);

Testing

Unit Testing

import { describe, it, expect, vi } from "vitest";
import { t402Client } from "@t402/core";
 
describe("t402Client", () => {
  it("should create payment payload", async () => {
    const client = new t402Client();
    const mockScheme = {
      createPaymentPayload: vi.fn().mockResolvedValue({
        t402Version: 2,
        authorization: { /* ... */ },
        signature: "0x...",
      }),
    };
 
    client.register("eip155:8453", mockScheme);
 
    const payload = await client.createPaymentPayload(requirements);
    expect(payload.t402Version).toBe(2);
  });
});

Integration Testing

import { describe, it, expect, beforeAll, afterAll } from "vitest";
import express from "express";
import { paymentMiddleware, t402ResourceServer } from "@t402/express";
 
describe("Payment Middleware", () => {
  let server: ReturnType<typeof express>;
 
  beforeAll(() => {
    server = express();
    server.use(paymentMiddleware(routes, resourceServer));
    server.get("/api/data", (req, res) => res.json({ data: "test" }));
    server.listen(3001);
  });
 
  it("should return 402 without payment", async () => {
    const response = await fetch("http://localhost:3001/api/data");
    expect(response.status).toBe(402);
 
    const body = await response.json();
    expect(body.t402Version).toBe(2);
    expect(body.accepts).toHaveLength(1);
  });
});

Mock Facilitator

import { MockFacilitatorClient } from "@t402/core/testing";
 
const mockFacilitator = new MockFacilitatorClient({
  verifyResponse: { isValid: true },
  settleResponse: { success: true, transaction: "0xmock..." },
});
 
const server = new t402ResourceServer(mockFacilitator);

Supported Networks

EVM Chains (USDT0)

ChainCAIP-2 Identifier
Ethereumeip155:1
Baseeip155:8453
Arbitrumeip155:42161
Optimismeip155:10
Polygoneip155:137
Inkeip155:57073
Berachaineip155:80094
Unichaineip155:130

Non-EVM Chains

ChainToken StandardCAIP-2 Identifier
SolanaSPL Tokensolana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp
TONJettonton:mainnet
TRONTRC-20tron:mainnet
NEARNEP-141near:mainnet
AptosFungible Assetaptos:1
TezosFA2tezos:NetXdQprcVkpaWU
PolkadotAsset Hubpolkadot:68d56f15f85d3136970ec16946040bc1
StacksSIP-010stacks:1

Development

# Clone and install
git clone https://github.com/t402-io/t402.git
cd t402/typescript
pnpm install
 
# Build all packages
pnpm build
 
# Run tests
pnpm test
 
# Type checking
pnpm typecheck
 
# Lint
pnpm lint

Monorepo Structure

sdks/typescript/
├── packages/
│   ├── core/           # @t402/core
│   ├── extensions/     # @t402/extensions
│   ├── mechanisms/
│   │   ├── evm/        # @t402/evm
│   │   ├── evm-core/   # @t402/evm-core
│   │   ├── svm/        # @t402/svm (Solana)
│   │   ├── ton/        # @t402/ton
│   │   ├── tron/       # @t402/tron
│   │   ├── near/       # @t402/near
│   │   ├── aptos/      # @t402/aptos
│   │   ├── tezos/      # @t402/tezos
│   │   ├── polkadot/   # @t402/polkadot
│   │   ├── stacks/     # @t402/stacks
│   │   └── btc/        # @t402/btc
│   ├── erc8004/         # @t402/erc8004
│   ├── http/
│   │   ├── express/    # @t402/express
│   │   ├── hono/       # @t402/hono
│   │   ├── fastify/    # @t402/fastify
│   │   ├── next/       # @t402/next
│   │   ├── fetch/      # @t402/fetch
│   │   ├── axios/      # @t402/axios
│   │   ├── paywall/    # @t402/paywall
│   │   ├── react/      # @t402/react
│   │   └── vue/        # @t402/vue
│   ├── wdk/            # @t402/wdk
│   ├── wdk-protocol/   # @t402/wdk-protocol
│   ├── wdk-gasless/    # @t402/wdk-gasless
│   ├── wdk-bridge/     # @t402/wdk-bridge
│   ├── wdk-multisig/   # @t402/wdk-multisig
│   ├── mcp/            # @t402/mcp
│   └── cli/            # @t402/cli
└── pnpm-workspace.yaml

Deep Dive

Requirements

  • Node.js 18+ or Bun 1.0+
  • TypeScript 5.0+ (recommended)
  • ESM or CommonJS supported