Skip to content

Comments

Custom code to support the x402 payment protocol in the SDK fetch/websockets#4

Open
rishabluthra wants to merge 5 commits intoagentmail-to:mainfrom
paysponge:main
Open

Custom code to support the x402 payment protocol in the SDK fetch/websockets#4
rishabluthra wants to merge 5 commits intoagentmail-to:mainfrom
paysponge:main

Conversation

@rishabluthra
Copy link

@rishabluthra rishabluthra commented Feb 15, 2026

Summary

Adds built-in support for the x402 payment protocol so HTTP API calls and WebSocket connections automatically handle 402 Payment Required responses.

  • Pass an x402Client to AgentMailClient — all API calls and WebSocket connections are payment-aware with zero extra code
  • Zero new hard dependencies — @x402/fetch is dynamically imported only when x402 option is provided
  • Uses Fern's custom code pattern: wrapper classes in src/wrapper/ extend generated classes,
    protected via .fernignore

Usage

HTTP

All REST API calls automatically handle 402 responses — the SDK intercepts the payment requirement, signs a USDC payment, and retries the request with a PAYMENT-SIGNATURE
header.

import { AgentMailClient, AgentMailEnvironment } from "agentmail";
import { x402Client } from "@x402/fetch";
import { registerExactEvmScheme } from "@x402/evm/exact/client";
import { registerExactSvmScheme } from "@x402/svm/exact/client";
import { privateKeyToAccount } from "viem/accounts";
import { createKeyPairSignerFromBytes } from "@solana/kit";
import { base58 } from "@scure/base";

// Create signers
const evmSigner = privateKeyToAccount("0x...");
const svmSigner = await createKeyPairSignerFromBytes(
  base58.decode("your-solana-private-key"),
);

// Create x402 client with EVM + SVM schemes
const x402 = new x402Client();
registerExactEvmScheme(x402, { signer: evmSigner });
registerExactSvmScheme(x402, { signer: svmSigner });

// Pass x402 client — all API calls handle payments automatically
const client = new AgentMailClient({
  environment: AgentMailEnvironment.ProdX402,
  x402,
});

// These just work — 402 responses are handled transparently
const inboxes = await client.inboxes.list();
const inbox = await client.inboxes.create({ username: "my-agent" });
await client.inboxes.messages.send(inbox.inboxId, {
  to: ["recipient@example.com"],
  subject: "Hello",
  text: "Sent via x402",
});

WebSocket

WebSocket endpoints don't natively support 402 responses, so the SDK probes the endpoint over HTTP first, signs the payment, then opens the WebSocket with the payment headers.

  // Same client from above — websockets are also payment-aware
  const socket = await client.websockets.connect();

  socket.on("message", (msg) => {
    console.log("Received:", msg);
  });

  socket.sendSubscribe({
    type: "subscribe",
    inboxIds: ["my-agent@agentmail.to"],
  });

Without x402

Existing usage is unchanged — if you don't pass x402, the client behaves exactly as before.

  const client = new AgentMailClient({
    environment: AgentMailEnvironment.Prod,
    apiKey: "your-api-key",
  });

Peer dependencies

When using x402, install the relevant packages:

  # Required
  npm install @x402/fetch

  # EVM (Base, Ethereum)
  npm install @x402/evm viem

  # SVM (Solana)
  npm install @x402/svm @solana/kit @scure/base

Summary by cubic

Adds built-in x402 payment support for both HTTP and WebSockets using a single x402 option on AgentMailClient. All 402 flows are handled automatically; existing usage is unchanged if you don’t pass x402.

  • New Features

    • Pass x402 to AgentMailClient — HTTP and WebSockets handle 402 automatically; no fetch override needed.
    • HTTP: SDK wraps fetch internally and pay-then-retries on 402.
    • WebSockets: probe over HTTP, sign payment, then connect with payment headers.
    • No API key required when x402 is provided; the SDK defaults it internally.
    • No hard dependency added; @x402/fetch is imported only when x402 is used.
  • Dependencies

    • Required: @x402/fetch
    • EVM: @x402/evm, viem
    • SVM: @x402/svm, @solana/kit, @scure/base

Written for commit d957f2c. Summary will update on new commits.

rishabluthra and others added 2 commits February 14, 2026 16:59
Extends the Fern-generated SDK with wrapper classes that automatically
handle x402 (402 Payment Required) flows when an x402Client is passed.
HTTP requests use wrapped fetch; WebSocket connections probe for payment
requirements and connect with signed payment headers.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@rishabluthra rishabluthra marked this pull request as ready for review February 15, 2026 01:07
@rishabluthra rishabluthra marked this pull request as draft February 15, 2026 01:08
Copy link

@cubic-dev-ai cubic-dev-ai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No issues found across 7 files

rishabluthra and others added 2 commits February 14, 2026 17:12
Users pass `wrapFetchWithPayment(fetch, x402)` via the existing `fetch`
option for HTTP. The SDK wrapper now only handles WebSocket x402 probing,
removing the lazy fetch init and X402Initialized abstraction.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The wrapper now calls wrapFetchWithPayment internally so users only
need to pass x402 once. No separate fetch override needed.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@rishabluthra rishabluthra marked this pull request as ready for review February 15, 2026 01:23
Copy link

@cubic-dev-ai cubic-dev-ai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No issues found across 7 files

Users no longer need to pass apiKey: "" when using x402.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant