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 } = 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}
    </div>
  );
}

Why This Is Better Than Wiring It Yourself

The hook consolidates:

  • payment state
  • request lifecycle
  • balances
  • transaction links
  • error handling

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
import { useX402Payment } from '@dexterai/x402/react';
 
export function PaidActionCard({ wallets }: { wallets: { solana?: unknown; evm?: unknown } }) {
  const { fetch, status, balances, transactionUrl } = 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}
    </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