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
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?
2. What is 3D Secure?
3. What should happen on payment failure?
4. What is the purpose of fraud scoring?
Flashcards
Question
Authorize vs Capture?
Click to reveal answer
Answer
Authorize reserves funds, capture charges card
Question
3D Secure purpose?
Click to reveal answer
Answer
Additional customer authentication for card payments
Question
Fraud scoring factors?
Click to reveal answer
Answer
Amount, velocity, address mismatch, country risk
Question
Payment failure handling?
Click to reveal answer
Answer
Retry with backoff, release inventory, notify customer
Question
Payment gateway fallback?
Click to reveal answer
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