Skip to main content

Online Checkout Integration

Accept stablecoin payments in your e-commerce checkout flow, mobile app, or any web-based payment experience.
Online checkout integration follows the same API pattern as POS terminals. The only difference is where the QR code is rendered — on a webpage or in a mobile app instead of a physical screen.

Overview

  1. Customer clicks “Pay with Crypto” at checkout
  2. Your server creates a payment intent
  3. Your frontend displays the QR code
  4. Customer scans with their mobile wallet and confirms
  5. Your server receives the webhook and fulfills the order

Step 1: Create Payment Intent (Server-Side)

// Your checkout API endpoint
app.post('/api/checkout/crypto', async (req, res) => {
  const { orderId, amount } = req.body;

  const response = await fetch('https://api.stablegenius.co/v1/payment-intents', {
    method: 'POST',
    headers: {
      'Authorization': `Bearer ${process.env.STABLEGENIUS_API_KEY}`,
      'Content-Type': 'application/json',
    },
    body: JSON.stringify({
      amount,
      currency: 'usd',
      merchant_id: process.env.MERCHANT_ID,
      metadata: { order_id: orderId },
      ttl: 600, // 10 minute timeout for online checkout
    }),
  });

  const paymentIntent = await response.json();

  res.json({
    payment_intent_id: paymentIntent.id,
    qr_payload: paymentIntent.qr_payload,
    qr_image_url: paymentIntent.qr_image_url,
    expires_at: paymentIntent.expires_at,
  });
});
Always create payment intents server-side. Never expose your API key in client-side JavaScript.

Step 2: Display QR Code (Client-Side)

<!-- Checkout page -->
<div id="crypto-payment">
  <h3>Scan to pay with USDC</h3>
  <img id="qr-code" alt="Payment QR Code" />
  <p id="status">Waiting for payment...</p>
  <p id="timer"></p>
</div>

<script>
  async function startCryptoPayment(orderId, amount) {
    // Create payment intent via your server
    const res = await fetch('/api/checkout/crypto', {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({ orderId, amount }),
    });
    const data = await res.json();

    // Display QR code
    document.getElementById('qr-code').src = data.qr_image_url;

    // Start countdown timer
    startTimer(data.expires_at);

    // Poll for payment confirmation
    pollForConfirmation(data.payment_intent_id);
  }

  async function pollForConfirmation(intentId) {
    const interval = setInterval(async () => {
      const res = await fetch(`/api/checkout/status?id=${intentId}`);
      const { status } = await res.json();

      if (status === 'confirmed') {
        clearInterval(interval);
        document.getElementById('status').textContent = 'Payment confirmed!';
        window.location.href = '/order/success';
      } else if (status === 'expired') {
        clearInterval(interval);
        document.getElementById('status').textContent = 'Payment expired. Please try again.';
      }
    }, 3000); // Poll every 3 seconds
  }
</script>
For lower latency, replace polling with a WebSocket or Server-Sent Events connection. Your backend pushes the confirmation to the frontend as soon as the webhook arrives, reducing perceived wait time from 3s (polling interval) to under 100ms.

Step 3: Handle Webhook and Fulfill Order

app.post('/webhooks/stablegenius', (req, res) => {
  res.status(200).json({ received: true });

  const event = req.body;

  if (event.type === 'payment_intent.confirmed') {
    const { metadata, amount } = event.data;

    // Fulfill the order
    fulfillOrder(metadata.order_id, { amount });

    // Send confirmation email
    sendConfirmationEmail(metadata.order_id);
  }
});

Mobile App Integration

For mobile apps, the same API works. Display the QR code in your app for the customer to scan with a separate wallet app, or use deep linking to open the customer’s wallet directly:
// React Native example
import { Linking } from 'react-native';

function openWalletForPayment(qrPayload) {
  // Attempt to open the QR payload as a deep link
  // Coinbase Wallet, MetaMask, and others handle EIP-681 URIs
  Linking.openURL(qrPayload).catch(() => {
    // Fallback: show QR code for manual scanning
    showQRCode(qrPayload);
  });
}

Shopify / E-Commerce Platforms

Shopify and WooCommerce plugins are on our roadmap. In the meantime, you can integrate via the API using a custom payment gateway. Contact us if you need help with platform-specific integration.