Skip to content

Checkout Flow

Detailed documentation of the crypto payment checkout process from start to finish.

Overview

The checkout flow consists of several stages:

  1. Checkout creation
  2. Payment initiation
  3. Payment detection
  4. Confirmation tracking
  5. Merchant settlement

Checkout Lifecycle


Stage 1: Checkout Creation

API Call:

bash
POST /api/v1/checkout/crypto

Request:

json
{
  "amount": 100.00,
  "currency": "USDT",
 "network": "BSC",
  "customer_email": "customer@example.com",
  "reference": "ORDER-12345",
  "callback_url": "https://yoursite.com/webhooks/payment",
  "metadata": {
    "custom_field": "value"
  }
}

Response:

json
{
  "checkout_id": "checkout_xyz789",
  "deposit_address": "0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb",
  "amount": "100.00",
  "currency": "USDT",
  "network": "BSC",
  "qr_code": "data:image/png;base64,iVBORw0KGgo...",
  "status": "pending",
  "expires_at": "2025-12-22T05:00:00Z",
  "created_at": "2025-12-22T04:30:00Z"
}

Stage 2: Payment Display

Display payment information to the customer with these key elements:

Required Information

  • Deposit Address - Exact address to send to
  • Amount - Precise amount to send
  • Currency - USDT or USDC
  • Network - BSC, ETH, POL, TRX, or SOL
  • QR Code - For mobile wallet scanning
  • Expiration Time - Countdown timer

Critical Warning

Always display a prominent warning about the network:

⚠️ IMPORTANT: Only send USDT on BSC network!
Sending on the wrong network will result in permanent loss of funds.

Stage 3: Payment Detection

Rach monitors the deposit address for incoming transactions:

Detection Methods

  1. Blockchain Polling (every 30 seconds)
  2. Webhook Notifications (if Tatum configured)

Payment Detected Event

When a payment is detected, you'll receive a webhook:

json
{
  "event": "payment.detected",
  "checkout_id": "checkout_xyz789",
  "txn_hash": "0x1234abc...",
  "amount": "100.00",
  "currency": "USDT",
  "network": "BSC",
  "confirmations": 0,
  "status": "paid",
  "timestamp": "2025-12-22T04:35:00Z"
}

Stage 4: Confirmation Tracking

Network Requirements

NetworkMin ConfirmationsAvg Time
BSC12~36 seconds
Ethereum12~3 minutes
Polygon128~4 minutes
Tron20~1 minute
Solana32~20 seconds

Confirmation Updates

You'll receive webhook updates as confirmations increase:

json
{
  "event": "payment.confirming",
  "checkout_id": "checkout_xyz789",
  "confirmations": 6,
  "required_confirmations": 12,
  "status": "confirming"
}

Fully Confirmed

json
{
  "event": "payment.confirmed",
  "checkout_id": "checkout_xyz789",
  "txn_hash": "0x1234abc...",
  "amount": "100.00",
  "confirmations": 12,
  "status": "confirmed",
  "timestamp": "2025-12-22T04:36:00Z"
}

Stage 5: Merchant Settlement

Once confirmed, the merchant balance is automatically credited:

Settlement Details:

  • Amount credited: Exact payment amount
  • Balance type: USDT or USDC
  • Network: Same as payment network
  • Instant: Credits immediately upon confirmation

Check Balance:

bash
GET /api/v1/balance/{merchant_id}

Edge Cases

Underpayment

If customer sends less than the required amount:

  • Status remains pending
  • Customer can send additional payment
  • Once total matches, payment proceeds

Overpayment

If customer sends more than required:

  • Payment completes for the checkout amount
  • Excess goes to merchant balance
  • Merchant can refund manually if needed

Wrong Network

If customer sends on wrong network:

  • Payment NOT detected by Rach
  • Funds may be permanently lost
  • Always display network warnings prominently

Expired Checkout

If payment arrives after expiration:

  • Payment still detected
  • Funds go to merchant balance
  • Webhook sent with expired status
  • Manual handling required

Status Transitions


Implementation Example

javascript
// Complete checkout flow implementation
class CryptoCheckoutFlow {
  constructor(rachPaymentService, orderService) {
    this.rachPaymentService = rachPaymentService;
    this.orderService = orderService;
  }
  
  async initiateCheckout(order) {
    // 1. Create checkout
    const checkout = await this.rachPaymentService.createCheckout({
      amount: order.total,
      currency: 'USDT',
      network: 'BSC',
      customer_email: order.customerEmail,
      reference: order.id,
      callback_url: `${process.env.BASE_URL}/webhooks/payment`
    });
    
    // 2. Store checkout_id with order
    await this.orderService.update(order.id, {
      checkout_id: checkout.checkout_id,
      payment_status: 'pending',
      expires_at: checkout.expires_at
    });
    
    // 3. Return payment details for display
    return {
      depositAddress: checkout.deposit_address,
      qrCode: checkout.qr_code,
      amount: checkout.amount,
      currency: checkout.currency,
      network: checkout.network,
      expiresAt: checkout.expires_at
    };
  }
  
  async handlePaymentWebhook(webhookPayload) {
    const { event, checkout_id, reference } = webhookPayload;
    
    switch (event) {
      case 'payment.detected':
        await this.orderService.update(reference, {
          payment_status: 'detected',
          txn_hash: webhookPayload.txn_hash
        });
        break;
        
      case 'payment.confirmed':
        await this.orderService.update(reference, {
          payment_status: 'confirmed',
          paid_at: new Date()
        });
        // Fulfill order
        await this.orderService.fulfill(reference);
        break;
        
      case 'payment.expired':
        await this.orderService.update(reference, {
          payment_status: 'expired'
        });
        break;
    }
  }
}

Best Practices

Checkout Flow Best Practices

  • ✅ Always generate unique deposit addresses per checkout
  • ✅ Store checkout_id with your order for tracking
  • ✅ Display countdown timer for checkout expiration
  • ✅ Show network prominently with warnings
  • ✅ Implement webhook handlers for all events
  • ✅ Handle partial payments gracefully
  • ✅ Provide customer support for stuck payments
  • ✅ Monitor for expired checkouts with payments

Troubleshooting

Payment Not Detected

  1. Verify customer sent to correct address
  2. Check transaction on block explorer
  3. Verify correct network used
  4. Check if enough confirmations

Payment Stuck

  1. Check blockchain congestion
  2. Verify transaction included in block
  3. Check confirmation count
  4. Contact support if needed

Wrong Amount

  1. Check for partial payments
  2. Verify decimals (USDT has 6 decimals on most networks)
  3. Check for multiple transactions

Next Steps

Built with ❤️ by Rach Finance