Dexter
Dexter
Docs

React

The React hooks are the most ergonomic path when you want a payment-aware UI instead of manually orchestrating status, balances, and retry state yourself.

useX402Payment

The main React entrypoint is useX402Payment.

import { useX402Payment } from '@dexterai/x402/react';
import { useWallet } from '@solana/wallet-adapter-react';
import { useAccount } from 'wagmi';
 
export function PayButton() {
  const solanaWallet = useWallet();
  const evmWallet = useAccount();
 
  const {
    fetch,
    isLoading,
    balances,
    transactionUrl,
    error,
    sponsoredRecommendations,
  } = useX402Payment({
    wallets: {
      solana: solanaWallet,
      evm: evmWallet,
    },
  });
 
  async function handlePay() {
    const response = await fetch('/api/protected');
    const data = await response.json();
    console.log(data);
  }
 
  return (
    <div>
      <p>Known balances: {balances.length}</p>
      <button onClick={handlePay} disabled={isLoading || !solanaWallet.connected}>
        {isLoading ? 'Paying...' : 'Pay and fetch'}
      </button>
      {transactionUrl ? <a href={transactionUrl}>View transaction</a> : null}
      {error ? <p>{error.message}</p> : null}
 
      {sponsoredRecommendations?.map((rec, i) => (
        <a key={i} href={rec.resourceUrl}>
          {rec.sponsor}: {rec.description}
        </a>
      ))}
    </div>
  );
}

When a payment settles and the facilitator returns sponsored recommendations, the hook automatically:

  1. Populates sponsoredRecommendations with typed SponsoredRecommendation[]
  2. Fires the impression beacon to confirm delivery to the ad network

The sponsoredRecommendations value is null until a payment completes with recommendations. It resets to null when you call reset().

See Sponsored Access for the full system.

Why This Is Better Than Wiring It Yourself

The hook consolidates:

  • payment state (status: idle, pending, success, error)
  • request lifecycle (402 detection, signing, settlement)
  • balances across all connected chains
  • transaction links (auto-generated explorer URLs)
  • error handling with typed X402Error codes
  • sponsored recommendation delivery and impression tracking

That is especially useful in applications where the same user may pay across more than one screen.

A practical pattern is:

  1. show whether the wallet is connected
  2. show known balance state
  3. keep the payment action explicit
  4. surface the transaction URL after settlement
  5. display sponsored recommendations if present
import { useX402Payment } from '@dexterai/x402/react';
 
export function PaidActionCard({ wallets }: { wallets: { solana?: unknown; evm?: unknown } }) {
  const {
    fetch, status, balances, transactionUrl, sponsoredRecommendations,
  } = useX402Payment({ wallets });
 
  async function run() {
    const res = await fetch('/api/report');
    const json = await res.json();
    console.log(json);
  }
 
  return (
    <section>
      <h3>Premium report</h3>
      <p>Status: {status}</p>
      <p>Balances tracked: {balances.length}</p>
      <button onClick={run}>Run paid action</button>
      {transactionUrl ? <a href={transactionUrl}>Open explorer</a> : null}
 
      {sponsoredRecommendations && (
        <div>
          <h4>Related tools</h4>
          {sponsoredRecommendations.map((rec, i) => (
            <a key={i} href={rec.resourceUrl}>{rec.sponsor}: {rec.description}</a>
          ))}
        </div>
      )}
    </section>
  );
}

When To Reach For useAccessPass

If your product has repeated reads against the same protected surface, useAccessPass usually creates a better UX than signing every request individually.

Read next:

On this page