← All Posts
Tutorials

Building a Crypto Checkout Page with React and Paychainly

May 21, 2026· 2 min read

What We're Building

A checkout page that: (1) creates a payment link, (2) shows the deposit address as a QR code, (3) counts down the 20-minute session, and (4) auto-confirms when payment arrives via WebSocket.

Step 1 — Create the Payment Link

const { data } = await axios.post('/api/create-payment', {
  amount: cart.total,
  productIds: cart.items.map(i => i.id),
});
// data.payUrl, data.depositAddress, data.expiresAt

Step 2 — QR Code Component

import QRCode from 'qrcode.react';

function CryptoCheckout({ depositAddress, amount, expiresAt }) {
  const [status, setStatus] = useState('pending');
  const secondsLeft = useCountdown(expiresAt);

  usePaymentWebhook(depositAddress, () => setStatus('confirmed'));

  if (status === 'confirmed') return <ThankYouScreen />;

  return (
    <div className="checkout">
      <QRCode value={depositAddress} size={200} />
      <p>Send exactly <strong>{amount} USDT (BEP-20)</strong></p>
      <p>to <code>{depositAddress}</code></p>
      <Countdown seconds={secondsLeft} />
    </div>
  );
}

Step 3 — Countdown Hook

function useCountdown(expiresAt) {
  const [left, setLeft] = useState(() => Math.max(0, (new Date(expiresAt) - Date.now()) / 1000));
  useEffect(() => {
    const id = setInterval(() => setLeft(s => Math.max(0, s - 1)), 1000);
    return () => clearInterval(id);
  }, []);
  return Math.floor(left);
}

Step 4 — WebSocket Hook

function usePaymentWebhook(depositAddress, onConfirmed) {
  useEffect(() => {
    const socket = io(API_URL);
    socket.emit('watchAddress', { depositAddress });
    socket.on('paymentConfirmed', onConfirmed);
    return () => socket.disconnect();
  }, [depositAddress]);
}

UX Best Practices

  • Warn users to send the exact amount — USDT amounts must match to the cent.
  • Show a "Session expired" screen if the countdown hits zero; offer to generate a new link.
  • Copy-to-clipboard button for the deposit address reduces user error.
← Back to Blog
Reactcheckoutfrontendcrypto paymentsUI