TypeScript SDK
useFetchWithPayment
A React hook that wraps the native fetch API to automatically handle 402 Payment Required responses using the x402 payment protocol with the currently connected wallet.
This hook enables you to make API calls that require payment without manually handling the payment flow.
Responses are automatically parsed as JSON by default (can be customized with parseAs option).
When a 402 response is received, it will automatically:
Parse the payment requirements
Verify the payment amount is within the allowed maximum
Create a payment header using the connected wallet
Retry the request with the payment header
If payment fails (e.g. insufficient funds), a modal will be shown to help the user resolve the issue. If no wallet is connected, a sign-in modal will be shown to connect a wallet.
import { useFetchWithPayment } from "thirdweb/react";import { createThirdwebClient } from "thirdweb"; const client = createThirdwebClient({ clientId: "your-client-id" }); function MyComponent() { const { fetchWithPayment, isPending } = useFetchWithPayment(client); const handleApiCall = async () => { // Response is automatically parsed as JSON const data = await fetchWithPayment( "https://api.example.com/paid-endpoint", ); console.log(data); }; return ( <button onClick={handleApiCall} disabled={isPending}> {isPending ? "Loading..." : "Make Paid API Call"} </button> );}const { fetchWithPayment } = useFetchWithPayment(client, { parseAs: "text", // Get response as text instead of JSON}); const textData = await fetchWithPayment( "https://api.example.com/endpoint",);const { fetchWithPayment } = useFetchWithPayment(client, { maxValue: 5000000n, // 5 USDC in base units theme: "light", paymentRequirementsSelector: (requirements) => { // Custom logic to select preferred payment method return requirements[0]; },});const { fetchWithPayment } = useFetchWithPayment(client, { fundWalletOptions: { title: "Add Funds", description: "You need more tokens to complete this payment", buttonLabel: "Get Tokens", },});const { fetchWithPayment } = useFetchWithPayment(client, { connectOptions: { wallets: [inAppWallet(), createWallet("io.metamask")], title: "Sign in to continue", },});const { fetchWithPayment, error } = useFetchWithPayment(client, { uiEnabled: false,}); // Handle the error manuallyif (error) { console.error("Payment failed:", error);}function useFetchWithPayment( options?: UseFetchWithPaymentConfig,): | { context: unknown; data: undefined; error: null; failureCount: number; failureReason: null | Error; fetchWithPayment: ( input: RequestInfo, init?: RequestInit, ) => Promise<unknown>; isError: false; isIdle: true; isPaused: boolean; isPending: false; isSuccess: false; mutate: UseMutateFunction< unknown, Error, { init?: RequestInit; input: RequestInfo }, unknown >; mutateAsync: UseMutateAsyncFunction< unknown, Error, { init?: RequestInit; input: RequestInfo }, unknown >; reset: () => void; status: "idle"; submittedAt: number; variables: undefined; } | { context: unknown; data: undefined; error: null; failureCount: number; failureReason: null | Error; fetchWithPayment: ( input: RequestInfo, init?: RequestInit, ) => Promise<unknown>; isError: false; isIdle: false; isPaused: boolean; isPending: true; isSuccess: false; mutate: UseMutateFunction< unknown, Error, { init?: RequestInit; input: RequestInfo }, unknown >; mutateAsync: UseMutateAsyncFunction< unknown, Error, { init?: RequestInit; input: RequestInfo }, unknown >; reset: () => void; status: "pending"; submittedAt: number; variables: { init?: RequestInit; input: RequestInfo }; } | { context: unknown; data: undefined; error: Error; failureCount: number; failureReason: null | Error; fetchWithPayment: ( input: RequestInfo, init?: RequestInit, ) => Promise<unknown>; isError: true; isIdle: false; isPaused: boolean; isPending: false; isSuccess: false; mutate: UseMutateFunction< unknown, Error, { init?: RequestInit; input: RequestInfo }, unknown >; mutateAsync: UseMutateAsyncFunction< unknown, Error, { init?: RequestInit; input: RequestInfo }, unknown >; reset: () => void; status: "error"; submittedAt: number; variables: { init?: RequestInit; input: RequestInfo }; } | { context: unknown; data: unknown; error: null; failureCount: number; failureReason: null | Error; fetchWithPayment: ( input: RequestInfo, init?: RequestInit, ) => Promise<unknown>; isError: false; isIdle: false; isPaused: boolean; isPending: false; isSuccess: true; mutate: UseMutateFunction< unknown, Error, { init?: RequestInit; input: RequestInfo }, unknown >; mutateAsync: UseMutateAsyncFunction< unknown, Error, { init?: RequestInit; input: RequestInfo }, unknown >; reset: () => void; status: "success"; submittedAt: number; variables: { init?: RequestInit; input: RequestInfo }; };let returnType: | { context: unknown; data: undefined; error: null; failureCount: number; failureReason: null | Error; fetchWithPayment: ( input: RequestInfo, init?: RequestInit, ) => Promise<unknown>; isError: false; isIdle: true; isPaused: boolean; isPending: false; isSuccess: false; mutate: UseMutateFunction< unknown, Error, { init?: RequestInit; input: RequestInfo }, unknown >; mutateAsync: UseMutateAsyncFunction< unknown, Error, { init?: RequestInit; input: RequestInfo }, unknown >; reset: () => void; status: "idle"; submittedAt: number; variables: undefined; } | { context: unknown; data: undefined; error: null; failureCount: number; failureReason: null | Error; fetchWithPayment: ( input: RequestInfo, init?: RequestInit, ) => Promise<unknown>; isError: false; isIdle: false; isPaused: boolean; isPending: true; isSuccess: false; mutate: UseMutateFunction< unknown, Error, { init?: RequestInit; input: RequestInfo }, unknown >; mutateAsync: UseMutateAsyncFunction< unknown, Error, { init?: RequestInit; input: RequestInfo }, unknown >; reset: () => void; status: "pending"; submittedAt: number; variables: { init?: RequestInit; input: RequestInfo }; } | { context: unknown; data: undefined; error: Error; failureCount: number; failureReason: null | Error; fetchWithPayment: ( input: RequestInfo, init?: RequestInit, ) => Promise<unknown>; isError: true; isIdle: false; isPaused: boolean; isPending: false; isSuccess: false; mutate: UseMutateFunction< unknown, Error, { init?: RequestInit; input: RequestInfo }, unknown >; mutateAsync: UseMutateAsyncFunction< unknown, Error, { init?: RequestInit; input: RequestInfo }, unknown >; reset: () => void; status: "error"; submittedAt: number; variables: { init?: RequestInit; input: RequestInfo }; } | { context: unknown; data: unknown; error: null; failureCount: number; failureReason: null | Error; fetchWithPayment: ( input: RequestInfo, init?: RequestInit, ) => Promise<unknown>; isError: false; isIdle: false; isPaused: boolean; isPending: false; isSuccess: true; mutate: UseMutateFunction< unknown, Error, { init?: RequestInit; input: RequestInfo }, unknown >; mutateAsync: UseMutateAsyncFunction< unknown, Error, { init?: RequestInit; input: RequestInfo }, unknown >; reset: () => void; status: "success"; submittedAt: number; variables: { init?: RequestInit; input: RequestInfo }; };An object containing:
fetchWithPayment: Function to make fetch requests with automatic payment handling (returns parsed data)isPending: Boolean indicating if a request is in progresserror: Any error that occurred during the requestdata: The parsed response data (JSON by default, or based onparseAsoption)Other mutation properties from React Query