wrapFetchWithPayment

Enables the payment of APIs using the x402 payment protocol.

This function wraps the native fetch API to automatically handle 402 Payment Required responses by creating and sending a payment header. It will:

  • Make the initial request

  • If a 402 response is received, parse the payment requirements

  • Verify the payment amount is within the allowed maximum

  • Create a payment header using the provided wallet client

  • Retry the request with the payment header

Example

import { wrapFetchWithPayment } from "thirdweb/x402";
import { createThirdwebClient } from "thirdweb";
import { createWallet } from "thirdweb/wallets";
const client = createThirdwebClient({ clientId: "your-client-id" });
const wallet = createWallet("io.metamask");
await wallet.connect({ client });
const fetchWithPay = wrapFetchWithPayment(fetch, client, wallet);
// Make a request that may require payment
const response = await fetchWithPay(
"https://api.example.com/paid-endpoint",
);
function wrapFetchWithPayment(
fetch: {
(input: URL | RequestInfo, init?: RequestInit): Promise<Response>;
(input: RequestInfo, init?: RequestInit): Promise<Response>;
(
input: string | Request | URL,
init?: RequestInit,
): Promise<Response>;
},
client: ThirdwebClient,
wallet: Wallet,
options?: {
maxValue?: bigint;
paymentRequirementsSelector?: (
paymentRequirements: Array<{
asset: string;
description: string;
extra?: Record<string, any>;
maxAmountRequired: string;
maxTimeoutSeconds: number;
mimeType: string;
network: string;
outputSchema?: Record<string, any>;
payTo: string;
resource: string;
scheme: "exact" | "upto";
}>,
) =>
| undefined
| {
asset: string;
description: string;
extra?: Record<string, any>;
maxAmountRequired: string;
maxTimeoutSeconds: number;
mimeType: string;
network: string;
outputSchema?: Record<string, any>;
payTo: string;
resource: string;
scheme: "exact" | "upto";
};
storage?: AsyncStorage;
},
): (input: RequestInfo, init?: RequestInit) => Promise<Response>;

Parameters

The fetch function to wrap (typically globalThis.fetch)

Type

let fetch: {
(input: URL | RequestInfo, init?: RequestInit): Promise<Response>;
(input: RequestInfo, init?: RequestInit): Promise<Response>;
(
input: string | Request | URL,
init?: RequestInit,
): Promise<Response>;
};

The thirdweb client used to access RPC infrastructure

Type

let client: {
readonly clientId: string;
readonly secretKey: string | undefined;
} & Readonly<ClientOptions>;

The wallet used to sign payment messages

Type

let wallet: {
getAdminAccount?: () => Account | undefined;
getAuthToken?: () => string | null;
getConfig: () => CreateWalletArgs<TWalletId>[1];
id: TWalletId;
onConnectRequested?: () => Promise<void>;
subscribe: WalletEmitter<TWalletId>["subscribe"];
autoConnect: (
options: WalletAutoConnectionOption<TWalletId>,
) => Promise<Account>;
connect: (
options: WalletConnectionOption<TWalletId>,
) => Promise<Account>;
disconnect: () => Promise<void>;
getAccount: () => undefined | Account;
getChain: () =>
| undefined
| Readonly<ChainOptions & { rpc: string }>;
switchChain: (chain: Readonly) => Promise<void>;
};

Type

let options: {
maxValue?: bigint;
paymentRequirementsSelector?: (
paymentRequirements: Array<{
asset: string;
description: string;
extra?: Record<string, any>;
maxAmountRequired: string;
maxTimeoutSeconds: number;
mimeType: string;
network: string;
outputSchema?: Record<string, any>;
payTo: string;
resource: string;
scheme: "exact" | "upto";
}>,
) =>
| undefined
| {
asset: string;
description: string;
extra?: Record<string, any>;
maxAmountRequired: string;
maxTimeoutSeconds: number;
mimeType: string;
network: string;
outputSchema?: Record<string, any>;
payTo: string;
resource: string;
scheme: "exact" | "upto";
};
storage?: AsyncStorage;
};

Returns

let returnType: (
input: RequestInfo,
init?: RequestInit,
) => Promise<Response>;

A wrapped fetch function that handles 402 responses automatically