Skip to main content

Usage

const {
  x402Fetch,
  payFetch,
  signPayment,
  isPaying,
  lastTxHash,
  lastAmount,
  lastPayment,
  totalSpent,
  error,
  paymentCount,
} = useX402Payment({
  wallet,
  encryptKey: pin,
  getBearerToken: getToken,
  maxPaymentAmount: "1.00",
});

Configuration

ParameterTypeRequiredDescription
walletWalletData | nullYesWallet data with publicKey and encryptedPrivateKey
encryptKeystringYesPIN or passkey-derived key for signing
getBearerToken() => Promise<string>NoFunction returning auth token (for session key path)
bearerTokenstringNoStatic bearer token (alternative to getBearerToken)
maxPaymentAmountstringNoMax USDC per payment in human-readable format (e.g. "1.00")
maxAmountstringNoAlias for maxPaymentAmount
allowedRecipientsstring[]NoWhitelist of recipient addresses. Empty = allow all
sessionSessionKeyData | nullNoActive session key for automatic payments without owner signature
onPaymentComplete(txHash: string, amount: string) => voidNoCallback fired after successful payment

Return Value

PropertyTypeDescription
x402Fetch(url: string, init?: RequestInit) => Promise<Response>Drop-in fetch replacement — auto-handles 402
payFetchSame as x402FetchAlias
signPayment(requirement: PaymentRequirement) => Promise<PaymentPayload>Manual payment signing for custom flows
isPayingbooleanWhether a payment is in progress
lastTxHashstring | nullLast payment transaction hash (session payments only — standard wallet returns null)
lastAmountstring | nullLast payment amount in human-readable USDC
lastPaymentLastPaymentInfo | nullLast payment details: { txHash, amount, timestamp }
totalSpentstringTotal USDC spent this session (e.g. "0.030000")
errorError | nullError from last payment attempt
paymentCountnumberTotal payments made this session

Example Implementation

import { useX402Payment, ChainToken } from "@chipi-stack/chipi-react";
import { useAuth } from "@clerk/nextjs";

export function PremiumApiClient({ wallet, pin }: { wallet: WalletData; pin: string }) {
  const { getToken } = useAuth();

  const {
    x402Fetch,
    isPaying,
    lastAmount,
    paymentCount,
    totalSpent,
    error,
  } = useX402Payment({
    wallet,
    encryptKey: pin,
    getBearerToken: getToken,
    maxPaymentAmount: "0.10", // Max 0.10 USDC per request
    onPaymentComplete: (txHash, amount) => {
      console.log(`Paid ${amount} USDC`);
    },
  });

  const handleQuery = async () => {
    // x402Fetch works like fetch — if the server returns 402,
    // the hook automatically signs and retries with X-PAYMENT header
    const response = await x402Fetch("https://api.example.com/premium/data");
    const data = await response.json();
    console.log("Response:", data);
  };

  return (
    <div>
      <button onClick={handleQuery} disabled={isPaying}>
        {isPaying ? "Paying..." : "Query Premium API"}
      </button>
      {lastAmount && <p>Last payment: {lastAmount} USDC</p>}
      <p>Total spent: {totalSpent} USDC ({paymentCount} payments)</p>
      {error && <p>Error: {error.message}</p>}
    </div>
  );
}

Payment Flows

Standard Wallet (no session)

  1. x402Fetch makes initial request
  2. Server returns 402 with PAYMENT-REQUIRED header
  3. Hook parses requirement, validates against maxPaymentAmount and allowedRecipients
  4. Signs SNIP-12 typed data locally via signTypedData() (no on-chain transaction)
  5. Retries with X-PAYMENT header containing the signed payload
  6. Facilitator settles the payment on-chain

Session Key (automatic payments)

  1. Same flow, but signs using session key via executeTransactionWithSession()
  2. Payment executes on-chain immediately (pre-signed)
  3. lastTxHash contains the actual transaction hash
  4. No owner signature needed — session key handles it

Security

  • maxPaymentAmount enforced before signing — prevents overpayment
  • allowedRecipients whitelist — prevents payment to unauthorized addresses
  • Only "exact" scheme and "starknet-mainnet" network accepted
  • Only USDC asset accepted (native USDC contract address validated)
  • Amount validation uses BigInt math (no float precision issues)
Standard wallet payments return lastTxHash: null because the signature is SNIP-12 off-chain — the facilitator settles on-chain later. Session payments return the actual transaction hash.