npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

react-next-402-coinbase-payments

v1.0.0

Published

Librería profesional para integrar pagos con protocolo 402 de Coinbase en aplicaciones React y Next.js

Downloads

16

Readme

React Next 402 Coinbase Payments

A comprehensive, enterprise-grade payment library for React and Next.js applications. Seamlessly integrates Coinbase Commerce API payments and native blockchain transactions through the innovative 402 Protocol. Perfect for e-commerce, SaaS subscriptions, NFT marketplaces, and Web3 applications.

✨ Key Features

💳 Coinbase Commerce Integration

  • Full API Support - Complete access to Coinbase Commerce features
  • Hosted Checkout - Professional payment pages with branding
  • Multi-Currency - USD, EUR, GBP, BTC, ETH, and 50+ fiat currencies
  • Subscription Management - Recurring payments and billing
  • Advanced Analytics - Detailed transaction reporting

🔗 Native Crypto Payments (v1.0.0)

  • Direct Blockchain Transactions - No intermediaries, instant settlements
  • Multi-Wallet Support - MetaMask, Phantom, Solflare, Trust, Coinbase, Brave, Opera
  • Multi-Chain Support - Ethereum, Polygon, BSC, Solana, Avalanche
  • Gas Optimization - Automatic gas estimation and network selection
  • True Ownership - Users control their funds directly

🛒 E-Commerce Ready

  • Product Integration - Easy integration with shopping carts
  • Dynamic Pricing - Support for discounts, taxes, and shipping
  • Order Management - Complete order lifecycle handling
  • Inventory Sync - Real-time inventory updates
  • Multi-Vendor - Support for marketplace scenarios

🏗️ Developer Experience

  • TypeScript First - Complete type safety and IntelliSense
  • React 18+ & Next.js 13+ - Modern framework support
  • Modular Architecture - Use only what you need
  • Comprehensive Documentation - Examples for every use case
  • Production Ready - Battle-tested in real applications

📦 Installation

npm install react-next-402-coinbase-payments

🔧 Environment Setup

Coinbase Commerce Configuration

# Get your API key from https://commerce.coinbase.com
COINBASE_API_KEY=your-production-api-key
COINBASE_WEBHOOK_SECRET=your-webhook-secret

Native Crypto Configuration (Optional)

# RPC endpoints for different networks (optional - uses public RPCs by default)
ETH_RPC_URL=https://mainnet.infura.io/v3/YOUR_PROJECT_ID
POLYGON_RPC_URL=https://polygon-rpc.com
BSC_RPC_URL=https://bsc-dataseed.binance.org
SOLANA_RPC_URL=https://api.mainnet-beta.solana.com
AVAX_RPC_URL=https://api.avax.network/ext/bc/C/rpc

🎯 Two Payment Modes

1. 💳 Coinbase Commerce Mode (API Key Required)

Best for: E-commerce, subscriptions, professional applications

  • Hosted checkout pages with your branding
  • Support for fiat currencies (USD, EUR, GBP) and credit cards
  • Advanced features: subscriptions, webhooks, analytics
  • PCI compliant and secure
  • Coinbase handles chargebacks and disputes

2. 🔗 Native Crypto Mode (No API Key Required)

Best for: Web3 apps, NFT marketplaces, DeFi platforms

  • Direct blockchain transactions - instant settlements
  • True user ownership of funds
  • Multi-chain support (ETH, Polygon, BSC, Solana, Avalanche)
  • Wallet integration (MetaMask, Phantom, Solflare, etc.)
  • No transaction fees deducted by payment processor

🛒 E-Commerce Integration Examples

Product Purchase with Shopping Cart

import { PaymentButton, use402Payment } from 'react-next-402-coinbase-payments';

function ProductCheckout({ product, cart }) {
  const { initiatePayment } = use402Payment({
    coinbaseApiKey: process.env.COINBASE_API_KEY,
    onPaymentSuccess: (result) => {
      // Update order status in your database
      updateOrderStatus(result.chargeId, 'paid');
      // Send confirmation email
      sendOrderConfirmation(product, cart);
    }
  });

  const handlePayment = () => {
    initiatePayment({
      amount: cart.total,
      currency: 'USD',
      description: `Purchase: ${product.name}`,
      metadata: {
        productId: product.id,
        cartId: cart.id,
        customerEmail: cart.customer.email
      }
    });
  };

  return (
    <div className="checkout-container">
      <div className="order-summary">
        <h3>Order Summary</h3>
        {cart.items.map(item => (
          <div key={item.id} className="cart-item">
            <span>{item.name}</span>
            <span>${item.price}</span>
          </div>
        ))}
        <div className="total">Total: ${cart.total}</div>
      </div>

      <PaymentButton
        coinbaseApiKey={process.env.COINBASE_API_KEY}
        paymentOptions={{
          amount: cart.total,
          currency: 'USD',
          description: `Order #${cart.id}`,
          metadata: { cartId: cart.id }
        }}
        onSuccess={(result) => {
          window.location.href = `/order/${result.chargeId}`;
        }}
      >
        Complete Purchase - ${cart.total}
      </PaymentButton>
    </div>
  );
}

Subscription Service

function SubscriptionCheckout({ plan }) {
  return (
    <PaymentButton
      coinbaseApiKey={process.env.COINBASE_API_KEY}
      paymentOptions={{
        amount: plan.price,
        currency: 'USD',
        description: `${plan.name} Subscription`,
        metadata: {
          planId: plan.id,
          billingCycle: plan.interval,
          userId: currentUser.id
        }
      }}
      onSuccess={async (result) => {
        // Create subscription in your database
        await createSubscription({
          userId: currentUser.id,
          planId: plan.id,
          chargeId: result.chargeId,
          status: 'active'
        });

        // Redirect to success page
        router.push('/subscription/success');
      }}
    >
      Subscribe to {plan.name} - ${plan.price}/{plan.interval}
    </PaymentButton>
  );
}

NFT Marketplace Purchase

function NFTPurchase({ nft }) {
  const { connectedWallet } = useWallet();

  return (
    <div className="nft-purchase">
      {connectedWallet ? (
        // Native crypto payment for NFT
        <NativePaymentButton
          amount={nft.price}
          currency="ETH"
          recipientAddress={nft.creatorAddress}
          onSuccess={(txHash) => {
            // Record NFT transfer
            recordNFTTransfer(nft.id, connectedWallet.address, txHash);
          }}
        >
          Buy NFT for {nft.price} ETH
        </NativePaymentButton>
      ) : (
        // Coinbase payment as fallback
        <PaymentButton
          coinbaseApiKey={process.env.COINBASE_API_KEY}
          paymentOptions={{
            amount: nft.price,
            currency: 'USD',
            description: `NFT: ${nft.name}`,
            metadata: { nftId: nft.id }
          }}
        >
          Buy NFT for ${nft.price}
        </PaymentButton>
      )}
    </div>
  );
}

🏦 Sandbox vs Production

Development (Sandbox) Configuration

// Use test API keys in development
const config = {
  coinbaseApiKey: process.env.NODE_ENV === 'production'
    ? process.env.COINBASE_PROD_KEY
    : process.env.COINBASE_SANDBOX_KEY,

  // Use test networks for native payments
  networks: process.env.NODE_ENV === 'production' ? {
    ethereum: 'https://mainnet.infura.io/v3/YOUR_KEY',
    polygon: 'https://polygon-rpc.com',
  } : {
    ethereum: 'https://sepolia.infura.io/v3/YOUR_KEY',
    polygon: 'https://rpc-mumbai.maticvigil.com',
  }
};

Environment Variables Setup

# .env.local (Development)
COINBASE_API_KEY=your_sandbox_api_key
COINBASE_WEBHOOK_SECRET=your_sandbox_webhook_secret
NODE_ENV=development

# .env.production (Production)
COINBASE_API_KEY=your_production_api_key
COINBASE_WEBHOOK_SECRET=your_production_webhook_secret
NODE_ENV=production

Test Mode Hook

import { useTestPayment } from 'react-next-402-coinbase-payments';

function DevelopmentPaymentTester() {
  const { simulatePayment, getAvailableScenarios } = useTestPayment({
    coinbaseApiKey: process.env.COINBASE_API_KEY,
    testMode: {
      enabled: process.env.NODE_ENV !== 'production',
      scenarios: [
        { id: 'success', name: 'Successful Payment', result: 'success' },
        { id: 'failed', name: 'Failed Payment', result: 'error' },
        { id: 'pending', name: 'Pending Payment', result: 'pending' }
      ]
    }
  });

  if (process.env.NODE_ENV === 'production') return null;

  return (
    <div className="test-mode-banner">
      <h4>Test Payment Scenarios</h4>
      {getAvailableScenarios().map(scenario => (
        <button
          key={scenario.id}
          onClick={() => simulatePayment(scenario.id)}
        >
          Test: {scenario.name}
        </button>
      ))}
    </div>
  );
}

🔧 RPC Configuration

Custom RPC Endpoints

// For better performance and reliability, configure custom RPC endpoints
const rpcConfig = {
  ethereum: {
    mainnet: 'https://mainnet.infura.io/v3/YOUR_PROJECT_ID',
    sepolia: 'https://sepolia.infura.io/v3/YOUR_PROJECT_ID'
  },
  polygon: {
    mainnet: 'https://polygon-mainnet.infura.io/v3/YOUR_PROJECT_ID',
    mumbai: 'https://polygon-mumbai.infura.io/v3/YOUR_PROJECT_ID'
  },
  bsc: {
    mainnet: 'https://bsc-dataseed.binance.org',
    testnet: 'https://data-seed-prebsc-1-s1.binance.org:8545'
  },
  solana: {
    mainnet: 'https://api.mainnet-beta.solana.com',
    devnet: 'https://api.devnet.solana.com'
  },
  avalanche: {
    mainnet: 'https://api.avax.network/ext/bc/C/rpc',
    fuji: 'https://api.avax-test.network/ext/bc/C/rpc'
  }
};

Network Switching

import { useWallet } from 'react-next-402-coinbase-payments';

function NetworkSwitcher() {
  const { connectedWallet, switchNetwork } = useWallet();

  const networks = [
    { id: '0x1', name: 'Ethereum Mainnet' },
    { id: '0x89', name: 'Polygon Mainnet' },
    { id: '0x38', name: 'BSC Mainnet' }
  ];

  return (
    <select
      onChange={(e) => switchNetwork(e.target.value)}
      disabled={!connectedWallet}
    >
      {networks.map(network => (
        <option key={network.id} value={network.id}>
          {network.name}
        </option>
      ))}
    </select>
  );
}

📚 Complete API Reference

PaymentButton Props

interface PaymentButtonProps {
  coinbaseApiKey: string;           // Required: Your Coinbase API key
  paymentOptions: PaymentOptions;   // Required: Payment configuration
  children: React.ReactNode;        // Required: Button content
  onSuccess?: (result: PaymentResult) => void;
  onError?: (error: string) => void;
  className?: string;
  disabled?: boolean;
  redirectUrl?: string;             // Override success redirect
  cancelUrl?: string;              // Override cancel redirect
}

PaymentOptions Interface

interface PaymentOptions {
  amount: number;                   // Payment amount
  currency: string;                // USD, EUR, GBP, BTC, ETH
  description?: string;            // Payment description
  metadata?: Record<string, any>;  // Custom metadata
  redirectUrl?: string;            // Success redirect URL
  cancelUrl?: string;              // Cancel redirect URL
  customerEmail?: string;          // Customer email for receipts
  customerName?: string;           // Customer name
}

useWallet Hook

const {
  connectedWallet,      // Current connected wallet info
  isConnecting,        // Connection loading state
  error,              // Connection error message
  wallets,            // Available wallet list
  connect,            // Connect wallet function
  disconnect,         // Disconnect wallet function
  switchNetwork       // Switch blockchain network
} = useWallet();

Webhook Handler

import { processWebhook, validateWebhookSignature } from 'react-next-402-coinbase-payments';

// API Route: /api/webhooks/coinbase
export default async function handler(req, res) {
  if (req.method !== 'POST') return res.status(405).end();

  const signature = req.headers['x-cc-webhook-signature'];

  // Validate webhook signature
  if (!validateWebhookSignature(
    JSON.stringify(req.body),
    signature,
    process.env.COINBASE_WEBHOOK_SECRET
  )) {
    return res.status(400).json({ error: 'Invalid signature' });
  }

  // Process webhook events
  processWebhook(req.body, {
    onChargeConfirmed: async (charge) => {
      await updateOrderStatus(charge.id, 'paid');
      await sendOrderConfirmation(charge);
    },
    onChargeFailed: (charge) => {
      console.error('Payment failed:', charge.id);
    },
    onChargePending: (charge) => {
      console.log('Payment pending:', charge.id);
    }
  });

  res.status(200).json({ received: true });
}

🚀 Deployment & Production

Environment Variables Checklist

# Required for Coinbase Commerce
COINBASE_API_KEY=your_production_api_key
COINBASE_WEBHOOK_SECRET=your_production_webhook_secret

# Optional for Native Crypto (uses public RPCs if not set)
ETH_RPC_URL=https://mainnet.infura.io/v3/YOUR_PROJECT_ID
POLYGON_RPC_URL=https://polygon-rpc.com
BSC_RPC_URL=https://bsc-dataseed.binance.org
SOLANA_RPC_URL=https://api.mainnet-beta.solana.com
AVAX_RPC_URL=https://api.avax.network/ext/bc/C/rpc

# Application settings
NODE_ENV=production
NEXT_PUBLIC_APP_URL=https://yourdomain.com

Coinbase Commerce Setup for Production

  1. Create Production Account at commerce.coinbase.com
  2. Generate API Keys in the dashboard
  3. Configure Webhooks:
    • URL: https://yourdomain.com/api/webhooks/coinbase
    • Events: charge:confirmed, charge:failed, charge:pending
  4. Set Webhook Secret in environment variables
  5. Test with Small Amounts before going live

Security Best Practices

// Always validate webhook signatures
import { validateWebhookSignature } from 'react-next-402-coinbase-payments';

if (!validateWebhookSignature(payload, signature, secret)) {
  return res.status(400).json({ error: 'Invalid signature' });
}

// Use HTTPS in production
const redirectUrls = {
  success: `${process.env.NEXT_PUBLIC_APP_URL}/payment/success`,
  cancel: `${process.env.NEXT_PUBLIC_APP_URL}/payment/cancel`
};

// Store sensitive data securely
const apiKey = process.env.COINBASE_API_KEY;
if (!apiKey) throw new Error('Coinbase API key not configured');

🔍 Troubleshooting

Common Issues

"Module not found" Error

# Clear node_modules and reinstall
rm -rf node_modules package-lock.json
npm install

# For Next.js, clear cache
rm -rf .next
npm run build

Webhook Signature Validation Fails

// Ensure you're using the raw request body
import { validateWebhookSignature } from 'react-next-402-coinbase-payments';

// For Next.js API routes
export const config = {
  api: {
    bodyParser: false, // Important for webhook signature validation
  },
};

const chunks = [];
for await (const chunk of req) {
  chunks.push(chunk);
}
const rawBody = Buffer.concat(chunks).toString();

const isValid = validateWebhookSignature(
  rawBody,
  req.headers['x-cc-webhook-signature'],
  process.env.COINBASE_WEBHOOK_SECRET
);

Wallet Connection Issues

// Check if wallet is installed
const { wallets } = useWallet();
const metamaskInstalled = wallets.find(w => w.type === 'metamask')?.installed;

// Handle connection errors
try {
  await connect('metamask');
} catch (error) {
  if (error.message.includes('User rejected')) {
    // Show user-friendly message
    alert('Please approve the connection in MetaMask');
  }
}

Network Switching Problems

// Add network to wallet if it doesn't exist
const addNetwork = async (chainId: string) => {
  try {
    await window.ethereum.request({
      method: 'wallet_addEthereumChain',
      params: [{
        chainId,
        chainName: 'Polygon Mainnet',
        nativeCurrency: { name: 'MATIC', symbol: 'MATIC', decimals: 18 },
        rpcUrls: ['https://polygon-rpc.com'],
        blockExplorerUrls: ['https://polygonscan.com']
      }]
    });
  } catch (error) {
    console.error('Failed to add network:', error);
  }
};

📊 Performance & Optimization

Bundle Size Optimization

// Import only what you need
import { PaymentButton } from 'react-next-402-coinbase-payments';
// Instead of importing everything

// Use dynamic imports for heavy components
import dynamic from 'next/dynamic';

const PaymentModal = dynamic(() =>
  import('react-next-402-coinbase-payments').then(mod => ({ default: mod.PaymentModal }))
);

Caching Strategies

// Cache payment configurations
const paymentConfig = useMemo(() => ({
  coinbaseApiKey: process.env.COINBASE_API_KEY,
  redirectUrl: `${baseUrl}/success`,
  cancelUrl: `${baseUrl}/cancel`
}), [baseUrl]);

Error Boundaries

class PaymentErrorBoundary extends React.Component {
  state = { hasError: false };

  static getDerivedStateFromError(error) {
    return { hasError: true };
  }

  componentDidCatch(error, errorInfo) {
    // Log to your error reporting service
    console.error('Payment error:', error, errorInfo);
  }

  render() {
    if (this.state.hasError) {
      return <div>Something went wrong with the payment system.</div>;
    }

    return this.props.children;
  }
}

🤝 Contributing

We welcome contributions! Please see our Contributing Guide for details.

Development Setup

git clone https://github.com/viainti/react-next-402-coinbase-payments.git
cd react-next-402-coinbase-payments
npm install
npm run demo  # Start development demo

Testing

npm test
npm run test:e2e  # End-to-end tests

📄 License

MIT License - see LICENSE file for details.

🆘 Support

🙏 Acknowledgments

  • Coinbase Commerce for their excellent payment API
  • The Web3 community for wallet standards
  • React and Next.js teams for amazing frameworks
  • All our contributors and early adopters

Built with ❤️ by Viainti


## 🚀 Demo

Try the library with our interactive demo!

### Run demo from root directory:
```bash
npm run demo

Or manually from demo directory:

cd demo
npm install
npm run dev

The demo runs on port 4020 (related to the 402 protocol).

Open http://localhost:4020 in your browser to see:

  • Interactive interface with usage examples
  • Functional PaymentButton component
  • use402Payment hook with programmatic handling
  • Result pages (success/cancellation)
  • API route for Coinbase webhooks

Basic Usage

Unified 402 Protocol (Recommended)

The easiest way to use the library with automatic method detection:

import { Payment402Button, use402Protocol } from 'react-next-402-coinbase-payments';

function App() {
  return (
    <Payment402Button
      coinbaseApiKey="your-api-key-here"
      paymentOptions={{
        amount: 25,
        currency: 'USD',
        description: 'Premium subscription',
        redirectUrl: 'https://yourapp.com/success',
        cancelUrl: 'https://yourapp.com/cancel',
      }}
      onSuccess={(result) => {
        console.log('402 Payment successful:', result);
        console.log('Method used:', result.method);
        console.log('Protocol:', result.protocol);
      }}
      onError={(error) => console.error('Payment error:', error)}
      showMethodSelector={true}
    >
      Pay with 402 Protocol
    </Payment402Button>
  );
}

Using the 402 Protocol Hook

import { use402Protocol } from 'react-next-402-coinbase-payments';

function PaymentComponent() {
  const { initiate402Payment, handle402Response, currentMethod, switchMethod } = use402Protocol({
    coinbaseApiKey: 'your-api-key-here',
    onPaymentSuccess: (result) => {
      console.log('402 Payment completed:', result);
    },
    onPaymentError: (error) => console.error('Error:', error)
  });

  const handlePayment = () => {
    initiate402Payment({
      amount: 10,
      currency: 'USD',
      description: 'Premium access'
    });
  };

  // Handle 402 responses automatically
  const handleApiResponse = async (response) => {
    if (response.status === 402) {
      await handle402Response(response.url, {
        amount: 10,
        currency: 'USD',
        description: 'Unlock content'
      });
    }
  };

  return (
    <div>
      <button onClick={handlePayment}>
        Pay with {currentMethod}
      </button>
      <button onClick={() => switchMethod('coinbase')}>
        Switch to Coinbase
      </button>
    </div>
  );
}

Coinbase Commerce Mode

Using the Hook

import { use402Payment } from 'react-next-402-coinbase-payments';

function PaymentComponent() {
  const { initiatePayment, isLoading } = use402Payment({
    coinbaseApiKey: 'your-api-key-here',
    onPaymentSuccess: (result) => {
      console.log('Payment successful:', result);
    },
    onPaymentError: (error) => {
      console.error('Payment error:', error);
    },
  });

  const handlePayment = () => {
    initiatePayment({
      amount: 10,
      currency: 'USD',
      description: 'Premium access',
      redirectUrl: 'https://yourapp.com/success',
      cancelUrl: 'https://yourapp.com/cancel',
    });
  };

  return (
    <button onClick={handlePayment} disabled={isLoading}>
      {isLoading ? 'Processing...' : 'Pay $10'}
    </button>
  );
}

Using the PaymentButton Component

import { PaymentButton } from 'react-next-402-coinbase-payments';

function App() {
  return (
    <PaymentButton
      coinbaseApiKey="your-api-key-here"
      paymentOptions={{
        amount: 25,
        currency: 'USD',
        description: 'Monthly subscription',
      }}
      onSuccess={(result) => console.log('Payment completed:', result)}
      onError={(error) => console.error('Error:', error)}
    >
      Subscribe for $25
    </PaymentButton>
  );
}

Native Crypto Mode (Coming Soon)

Using Wallet Connection

import { WalletConnectButton, NativePaymentButton } from 'react-next-402-coinbase-payments';

function CryptoPaymentComponent() {
  return (
    <div>
      <WalletConnectButton />

      <NativePaymentButton
        recipientAddress="0x..."
        amount={0.01}
        currency="ETH"
        description="NFT Purchase"
        onSuccess={(result) => console.log('Crypto payment successful:', result.txHash)}
        onError={(error) => console.error('Crypto payment error:', error)}
      >
        Pay 0.01 ETH
      </NativePaymentButton>
    </div>
  );
}

Using the Native Payment Hook

import { useNativePayment } from 'react-next-402-coinbase-payments';

function CustomCryptoPayment() {
  const { sendPayment, isProcessing, estimateCost } = useNativePayment();

  const handlePayment = async () => {
    const result = await sendPayment({
      amount: 0.05,
      currency: 'MATIC',
      recipientAddress: '0x...',
      description: 'Service payment'
    });

    if (result.success) {
      console.log('Payment sent:', result.txHash);
    }
  };

  return (
    <button onClick={handlePayment} disabled={isProcessing}>
      {isProcessing ? 'Sending...' : 'Send 0.05 MATIC'}
    </button>
  );
}

Wallet Connection

Using the WalletConnectButton

import { WalletConnectButton } from 'react-next-402-coinbase-payments';

function WalletSection() {
  return (
    <WalletConnectButton
      onConnect={(wallet) => {
        console.log('Connected:', wallet.address);
      }}
      onDisconnect={() => {
        console.log('Disconnected');
      }}
      showWalletList={true}
    />
  );
}

Using the useWallet Hook

import { useWallet } from 'react-next-402-coinbase-payments';

function CustomWalletConnection() {
  const {
    connectedWallet,
    isConnecting,
    error,
    getAvailableWallets,
    connect,
    disconnect,
    switchNetwork
  } = useWallet();

  const handleConnect = async () => {
    const availableWallets = getAvailableWallets();
    if (availableWallets.length > 0) {
      await connect(availableWallets[0].type);
    }
  };

  return (
    <div>
      {connectedWallet ? (
        <div>
          <p>Connected: {connectedWallet.address}</p>
          <button onClick={disconnect}>Disconnect</button>
        </div>
      ) : (
        <button onClick={handleConnect} disabled={isConnecting}>
          {isConnecting ? 'Connecting...' : 'Connect Wallet'}
        </button>
      )}
      {error && <p>Error: {error}</p>}
    </div>
  );
}

Supported Wallets

| Wallet | Type | Chains | Detection | |--------|------|--------|-----------| | MetaMask | EIP-1193 | ETH, Polygon, BSC, Avalanche | window.ethereum.isMetaMask | | Phantom | Solana | Solana | window.solana.isPhantom | | Solflare | Solana | Solana | window.solflare | | Trust Wallet | EIP-1193 | ETH, Polygon, BSC | window.ethereum.isTrust | | Coinbase Wallet | EIP-1193 | ETH, Polygon, BSC | window.ethereum.isCoinbaseWallet | | Brave Wallet | EIP-1193 | ETH, Polygon, BSC | window.ethereum.isBraveWallet | | Opera Wallet | EIP-1193 | ETH, Polygon, BSC | window.ethereum.isOpera |

Webhook Handling

To process Coinbase webhooks, set up an endpoint on your server:

import { processWebhook, validateWebhookSignature } from 'react-next-402-coinbase-payments';

// In your API route (Next.js)
export default async function handler(req, res) {
  if (req.method === 'POST') {
    const signature = req.headers['x-cc-webhook-signature'];
    const payload = JSON.stringify(req.body);

    // Validate signature (optional but recommended)
    if (!validateWebhookSignature(payload, signature, 'your-webhook-secret')) {
      return res.status(400).json({ error: 'Invalid signature' });
    }

    // Process webhook
    processWebhook(req.body, {
      onChargeConfirmed: (charge) => {
        console.log('Payment confirmed:', charge.id);
        // Update database, grant access, etc.
      },
      onChargeFailed: (charge) => {
        console.log('Payment failed:', charge.id);
      },
      onChargePending: (charge) => {
        console.log('Payment pending:', charge.id);
      },
    });

    res.status(200).json({ received: true });
  }
}

API Reference

use402Payment

Main hook for handling payments.

Parameters:

  • coinbaseApiKey: Your Coinbase Commerce API key
  • onPaymentSuccess: Callback when payment is successful
  • onPaymentError: Callback when there's an error

Returns:

  • initiatePayment: Function to initiate a payment
  • handle402Response: Function to handle 402 responses
  • checkPaymentStatus: Function to check payment status
  • isLoading: Loading state
  • paymentResult: Result of the last payment

PaymentButton

Button component for payments.

Props:

  • coinbaseApiKey: Required API key
  • paymentOptions: Payment options
  • children: Button content
  • onSuccess: Success callback
  • onError: Error callback
  • className: CSS classes
  • disabled: Disable button

Types

interface PaymentOptions {
  amount: number;
  currency: string;
  description?: string;
  metadata?: Record<string, any>;
  redirectUrl?: string;
  cancelUrl?: string;
}

interface PaymentResult {
  success: boolean;
  chargeId?: string;
  error?: string;
  redirectUrl?: string;
}

402 Protocol

This library implements the HTTP 402 (Payment Required) protocol for web payments. When a resource requires payment, the server can return a 402 response with information on how to pay using cryptocurrencies through Coinbase.

Contributing

Contributions are welcome! Please open an issue or pull request on GitHub.

License

MIT