Skip to content
advanced Phase 104 · Commerce Design Advanced

Payment System Design

45m
1 problems
Topic Progress 0%

Payment System Overview

Payment Flow

1. Customer enters payment details
2. Tokenize sensitive data
3. Send to payment gateway
4. Gateway validates
5. Bank authorizes
6. Authorization response
7. Capture funds (immediate or delayed)
8. Update order status
9. Send confirmation

Payment Methods

Offline Methods:
├── Check / Money order
├── Bank transfer
└── Cash on delivery

Online Methods:
├── Credit cards (Stripe, Braintree)
├── PayPal
├── Apple Pay / Google Pay
└── Local payment methods

Digital Wallets:
├── PayPal
├── Venmo
└── Amazon Pay

Data Model

-- Payment method table
CREATE TABLE sales_order_payment (
    entity_id INT AUTO_INCREMENT PRIMARY KEY,
    order_id INT,
    method VARCHAR(32),
    additional_data TEXT,
    po_number VARCHAR(255),
    cc_type VARCHAR(32),
    cc_last_4 VARCHAR(4),
    cc_exp_month INT,
    cc_exp_year INT
);

-- Payment transaction table
CREATE TABLE sales_order_payment_transaction (
    transaction_id INT AUTO_INCREMENT PRIMARY KEY,
    payment_id INT,
    order_id INT,
    txn_id VARCHAR(255),
    parent_txn_id VARCHAR(255),
    txn_type VARCHAR(32),
    amount DECIMAL(12,4),
    status VARCHAR(32),
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    additional_info TEXT
);

Gateway Integration

Gateway Interface

// Payment gateway interface
class GatewayInterface
{
    public function authorize(PaymentInterface $payment, $amount);
    public function capture(PaymentInterface $payment, $amount);
    public function void(PaymentInterface $payment);
    public function refund(PaymentInterface $payment, $amount);
    public function getAvailableMethods();
}

// Gateway configuration
$gatewayConfig = [
    'stripe' => [
        'api_key' => $config->getApiKey(),
        'publishable_key' => $config->getPublishableKey(),
        'test_mode' => $config->isTestMode(),
    ],
    'paypal' => [
        'client_id' => $config->getClientId(),
        'client_secret' => $config->getClientSecret(),
        'sandbox' => $config->isSandbox(),
    ]
];

Stripe Integration

// Stripe implementation
class StripeGateway implements GatewayInterface
{
    public function authorize($payment, $amount)
    {
        try {
            $charge = $this->stripe->charges->create([
                'amount' => round($amount * 100),
                'currency' => $payment->getOrder()->getCurrencyCode(),
                'source' => $payment->getToken(),
                'capture' => false,
                'metadata' => [
                    'order_id' => $payment->getOrder()->getIncrementId(),
                    'customer_email' => $payment->getOrder()->getCustomerEmail()
                ]
            ]);
            
            $payment->setTransactionId($charge->id);
            $payment->setIsTransactionClosed(false);
            
            return $charge;
            
        } catch (\Stripe\Exception\CardError $e) {
            throw new \Magento\Framework\Exception\LocalizedException(
                __('Card declined: ' . $e->getMessage())
            );
        }
    }
    
    public function capture($payment, $amount)
    {
        $charge = $this->stripe->charges->capture(
            $payment->getTransactionId(),
            ['amount' => round($amount * 100)]
        );
        
        $payment->setIsTransactionClosed(true);
        return $charge;
    }
}

PayPal Integration

// PayPal implementation
class PayPalGateway implements GatewayInterface
{
    public function authorize($payment, $amount)
    {
        $order = $this->paypal->createOrder([
            'intent' => 'CAPTURE',
            'purchase_units' => [[
                'amount' => [
                    'currency_code' => $payment->getOrder()->getCurrencyCode(),
                    'value' => $amount
                ]
            ]],
            'application_context' => [
                'return_url' => $this->getReturnUrl(),
                'cancel_url' => $this->getCancelUrl()
            ]
        ]);
        
        $payment->setTransactionId($order->id);
        return $order;
    }
}

Fraud Prevention

Fraud Detection Rules

// Fraud check service
class FraudCheckService
{
    public function check($order)
    {
        $score = 0;
        $checks = [];
        
        // 1. Amount check
        if ($order->getGrandTotal() > 500) {
            $score += 20;
            $checks[] = 'High amount: ' . $order->getGrandTotal();
        }
        
        // 2. Velocity check
        $recentOrders = $this->getRecentOrders(
            $order->getCustomerEmail(),
            24 // hours
        );
        if (count($recentOrders) > 3) {
            $score += 30;
            $checks[] = 'High velocity: ' . count($recentOrders) . ' orders in 24h';
        }
        
        // 3. Address mismatch
        if ($order->getShippingAddress() != $order->getBillingAddress()) {
            $score += 15;
            $checks[] = 'Address mismatch';
        }
        
        // 4. High-risk country
        $highRiskCountries = ['NG', 'GH', 'PK', 'BD'];
        if (in_array($order->getShippingCountry(), $highRiskCountries)) {
            $score += 10;
            $checks[] = 'High-risk country: ' . $order->getShippingCountry();
        }
        
        // 5. IP geolocation
        if ($this->isIpFromDifferentCountry($order)) {
            $score += 15;
            $checks[] = 'IP geolocation mismatch';
        }
        
        // 6. Email age
        if ($this->isEmailNew($order->getCustomerEmail())) {
            $score += 10;
            $checks[] = 'New email address';
        }
        
        return [
            'score' => $score,
            'checks' => $checks,
            'action' => $this->getAction($score)
        ];
    }
    
    private function getAction($score)
    {
        if ($score >= 50) {
            return 'hold';
        } elseif ($score >= 30) {
            return 'review';
        } else {
            return 'approve';
        }
    }
}

3D Secure

// 3D Secure authentication
public function authenticate3ds($payment, $amount)
{
    $authentication = $this->stripe->paymentIntents->create([
        'amount' => round($amount * 100),
        'currency' => $payment->getOrder()->getCurrencyCode(),
        'payment_method' => $payment->getToken(),
        'confirmation_method' => 'manual',
        'confirm' => true,
        'return_url' => $this->getReturnUrl()
    ]);
    
    if ($authentication->status === 'requires_action') {
        return [
            'requires_action' => true,
            'client_secret' => $authentication->client_secret
        ];
    }
    
    return [
        'requires_action' => false,
        'transaction_id' => $authentication->id
    ];
}

Payment Failure Handling

Failure Types

Card declined:
├── Insufficient funds
├── Card expired
├── Invalid card number
├── Wrong CVV
├── Card blocked
└── Bank declined

Gateway errors:
├── Network timeout
├── API error
├── Service unavailable
└── Invalid response

Processing errors:
├── Duplicate transaction
├── Amount mismatch
├── Currency mismatch
└── Invalid token

Retry Logic

// Payment retry service
class PaymentRetryService
{
    public function retry($order, $maxRetries = 3)
    {
        $attempts = 0;
        $lastError = null;
        
        while ($attempts < $maxRetries) {
            try {
                $result = $this->paymentService->process($order);
                return $result;
                
            } catch (\Exception $e) {
                $lastError = $e;
                $attempts++;
                
                // Wait before retry (exponential backoff)
                $delay = pow(2, $attempts) * 1000; // 2s, 4s, 8s
                usleep($delay * 1000);
                
                // Log retry attempt
                $this->logger->warning('Payment retry ' . $attempts, [
                    'order_id' => $order->getId(),
                    'error' => $e->getMessage()
                ]);
            }
        }
        
        // All retries failed
        $this->handlePermanentFailure($order, $lastError);
        throw $lastError;
    }
    
    private function handlePermanentFailure($order, $error)
    {
        // Update order status
        $order->setState('new', 'Payment failed');
        $order->addStatusHistoryComment(
            'Payment failed: ' . $error->getMessage()
        );
        $order->save();
        
        // Release inventory
        $this->inventoryService->releaseOrder($order);
        
        // Notify customer
        $this->emailService->sendPaymentFailed($order, $error);
        
        // Notify admin
        $this->adminNotifier->notify(
            'Payment failed for order ' . $order->getIncrementId()
        );
    }
}

Graceful Degradation

// Fallback to alternative payment method
public function processWithFallback($order)
{
    try {
        // Try primary gateway
        return $this->primaryGateway->authorize($order);
        
    } catch (\Exception $e) {
        $this->logger->warning('Primary gateway failed', [
            'error' => $e->getMessage()
        ]);
        
        // Fallback to secondary gateway
        try {
            return $this->secondaryGateway->authorize($order);
            
        } catch (\Exception $e2) {
            $this->logger->error('All gateways failed', [
                'primary_error' => $e->getMessage(),
                'secondary_error' => $e2->getMessage()
            ]);
            
            throw new \Exception('Payment processing unavailable');
        }
    }
}

Practice Problems

0 / 1 solved
Payment System Design

Design payment system with multiple gateways, fraud prevention, and retry logic.

Solution
// System:
// 1. Gateways: Stripe (primary), PayPal (secondary)
// 2. Flow: Tokenize → Authorize → Capture
// 3. Fraud: Score check, 3DS for high risk
// 4. Retry: 3 attempts with backoff
// 5. Fallback: Primary → Secondary
// 6. Notify: Email on success/failure

Quiz

1. What is the difference between authorize and capture?

Question 1 options

2. What is 3D Secure?

Question 2 options

3. What should happen on payment failure?

Question 3 options

4. What is the purpose of fraud scoring?

Question 4 options

Flashcards

Question

Authorize vs Capture?

Answer

Authorize reserves funds, capture charges card

Question

3D Secure purpose?

Answer

Additional customer authentication for card payments

Question

Fraud scoring factors?

Answer

Amount, velocity, address mismatch, country risk

Question

Payment failure handling?

Answer

Retry with backoff, release inventory, notify customer

Question

Payment gateway fallback?

Answer

Try primary, fallback to secondary on failure

Revision Notes

Key Takeaways

  • 1. Authorize: Reserve funds; Capture: Charge card
  • 2. 3D Secure: Additional authentication layer
  • 3. Fraud scoring: Amount, velocity, address, country
  • 4. Failure: Retry → Release inventory → Notify
  • 5. Fallback: Primary → Secondary gateway

Interview Tips

  • Explain authorize vs capture flow
  • Discuss fraud prevention strategies
  • Know payment failure handling
  • Understand 3D Secure purpose

Cheat Sheet

Payment System

  • Authorize: Reserve funds
  • Capture: Charge card
  • 3D Secure: Customer authentication
  • Fraud: Amount, velocity, address, country
  • Failure: Retry → Release → Notify
  • Fallback: Primary → Secondary