Comprehensive guide on how to handle online payments using ASP.NET Core and React.js

Muhammad Salem - Jul 23 - - Dev Community

Online payments involve a complex dance between several parties to securely transfer funds from a buyer to a seller over the internet. Here's a detailed breakdown of the steps involved:

1. Buyer Initiates Purchase:

  • You browse an online store and add items to your virtual shopping cart.
  • When you proceed to checkout, you'll enter your billing and shipping information.

2. Payment Method Selection:

  • You choose your preferred payment method, which could be:
    • Credit Card
    • Debit Card
    • Digital Wallet (e.g., Apple Pay, Google Pay)
    • Online Payment Processor (e.g., PayPal)

3. Payment Processing:

  • This stage depends on the chosen payment method:

    • Credit/Debit Card:
      • The website securely transmits your card information (encrypted) to the payment gateway.
      • Payment Gateway: This acts as a secure intermediary between the website and your bank. It doesn't store your actual card details but creates a temporary token for the transaction.
      • Authorization Request: The payment gateway sends an authorization request to your card network (e.g., Visa, Mastercard).
      • Card Network: The network forwards the request to your card-issuing bank for verification.
      • Bank Verification: Your bank checks your account balance and verifies if the transaction is within your spending limits or fraud checks.
    • Digital Wallet:
      • The digital wallet app on your phone communicates with the payment gateway using Near Field Communication (NFC) or a secure online connection.
      • The digital wallet transmits a one-time use token linked to your card, not the actual card number.
      • The verification process then follows a similar flow as with credit/debit cards, contacting your card network and bank for authorization.
    • Online Payment Processor:
      • If you use a platform like PayPal, the website redirects you to PayPal's login page.
      • You log in to your PayPal account and choose your funding source (PayPal balance, linked bank account, etc.).
      • PayPal debits your chosen funding source and transfers the money to the merchant's account.

4. Approval or Decline:

  • Based on the verification results, your bank or the payment processor (for PayPal) sends an approval or decline message back to the merchant's payment gateway.

5. Transaction Settlement:

  • Upon Approval:

    • The payment gateway sends a confirmation signal to the website, indicating a successful transaction.
    • The website then processes your order and prepares it for shipment.
    • Your bank account or chosen funding source is debited for the purchase amount.
    • The merchant's bank account receives the corresponding funds (minus any processing fees).
  • Upon Decline:

    • The website receives a decline notification and informs you that the payment was unsuccessful.
    • You'll need to choose another payment method or troubleshoot the issue with your bank.

6. Order Fulfillment and Delivery:

  • The merchant fulfills your order by picking, packing, and shipping the purchased items to your designated address.
  • You'll typically receive a notification with tracking information to follow the shipment's progress.

Additional Considerations:

  • Security Measures: Throughout this process, various security measures are implemented to protect your financial information. Encryption is used to scramble data transmissions, and tokenization replaces your actual card number with temporary tokens during authorization.
  • Fraud Prevention: Banks and payment processors employ fraud detection systems to monitor transactions for suspicious activity and potentially block fraudulent purchases.
  • Timeframes: The speed of online payments can vary depending on the payment method and the banks involved.
    • Credit/debit card transactions are usually very fast, often completed within seconds.
    • Transfers using online payment processors may take a bit longer, depending on their internal processes.

Overall, online payments involve a complex but well-coordinated effort between various parties to ensure a secure and efficient way to shop online.
In this article I will provide a detailed breakdown of online payments. This is indeed a complex topic, so let's dive in step by step.

  1. Payment Gateway Integration: As a software engineer, your first step would be to integrate a payment gateway into your ecommerce application. A payment gateway is a service that authorizes and processes payments for online businesses.

Popular payment gateways include Stripe, PayPal, Square, and Braintree. You'll need to sign up for an account with one of these providers and integrate their API (Application Programming Interface) into your application.

  1. Payment Flow:

a. Customer Checkout:

  • The customer selects items and proceeds to checkout in your ecommerce app.
  • They enter their payment details (credit card number, expiration date, CVV, etc.) into a form.

b. Data Encryption:

  • Before sending sensitive data, you need to encrypt it. Most payment gateways provide client-side libraries (usually JavaScript) to handle this.
  • The data is typically encrypted using public key cryptography, where only the payment gateway has the private key to decrypt the information.

c. Token Generation:

  • Instead of sending raw card details to your server, modern systems use tokenization.
  • The encrypted payment data is sent to the payment gateway, which returns a token representing the payment method.
  • This token is then sent to your server, enhancing security as you never handle raw card data.

d. Payment Request:

  • Your server creates a payment request to the payment gateway, including the token, amount, and any other relevant details.

e. Payment Processing:

  • The payment gateway forwards the request to the appropriate card network (Visa, MasterCard, etc.).
  • The card network routes the request to the issuing bank (the customer's bank).

f. Authorization:

  • The issuing bank checks if the customer has sufficient funds and if the transaction seems legitimate.
  • They send an approval or denial back through the chain.

g. Confirmation:

  • The payment gateway receives the response and forwards it to your server.
  • Your server updates the order status and informs the customer of the result.
  1. Security Considerations:

a. PCI DSS Compliance:

  • If you're handling card data, you need to comply with the Payment Card Industry Data Security Standard (PCI DSS).
  • Using a reputable payment gateway and tokenization can significantly reduce your compliance burden.

b. SSL/TLS:

  • Ensure all communications are encrypted using SSL/TLS (HTTPS).

c. Input Validation:

  • Implement strong input validation to prevent injection attacks.

d. Error Handling:

  • Implement proper error handling without revealing sensitive information.
  1. Handling Different Payment Methods: Besides credit cards, you may want to support methods like:
  2. PayPal
  3. Apple Pay / Google Pay
  4. Bank transfers (ACH in the US)
  5. Cryptocurrency

Each method may require different integration steps.

  1. Recurring Payments: If you're offering subscriptions, you'll need to implement recurring payment logic:
  2. Store payment method tokens securely
  3. Set up a system to automatically initiate payments at set intervals
  4. Handle failed payments and retries

  5. Refunds and Chargebacks:
    Implement functionality to process refunds through your payment gateway's API. Be prepared to handle chargebacks, which occur when a customer disputes a charge with their bank.

  6. Webhooks:
    Most payment gateways use webhooks to send real-time updates about transactions. You'll need to set up endpoints to receive and process these notifications.

  7. Testing:
    Payment gateways typically provide sandbox environments for testing. Use these extensively before going live.

  8. Logging and Monitoring:
    Implement comprehensive logging for all payment-related activities. Set up monitoring and alerting for any unusual patterns or errors.

  9. Internationalization:
    If you're selling internationally, consider:

  10. Multiple currencies

  11. Local payment methods

  12. Tax calculations

  13. Compliance with local regulations (e.g., GDPR in Europe)

  14. Mobile Considerations:
    If you're building a mobile app, you may need to use specific SDKs provided by payment gateways for iOS and Android.

  15. Analytics and Reporting:
    Implement systems to track and analyze payment data, helping with business decisions and fraud detection.

This overview covers the main aspects of implementing online payments from a software engineering perspective. Remember, while it's crucial to understand these concepts, many of the complex security aspects are handled by established payment gateways. Your main focus will be on correctly integrating with their systems and ensuring your application handles the flow properly.

As you start implementing, I recommend diving deeper into the specific documentation of your chosen payment gateway, as each one has its unique APIs and best practices.

Now I'll walk you through building a simplified version of an Amazon-like system, focusing on the payment process. We'll use C# with ASP.NET Core Web API for the backend, Entity Framework Core for database operations, and React.js for the frontend. I'll provide code snippets and explanations for each part of the system.

Let's break this down into steps:

  1. Database Design
  2. Backend API
  3. Frontend Implementation
  4. Payment Gateway Integration
  5. Order Processing

  6. Database Design

First, let's define our database models using Entity Framework Core:

// Product.cs
public class Product
{
    public int Id { get; set; }
    public string Name { get; set; }
    public decimal Price { get; set; }
    public string Description { get; set; }
}

// Order.cs
public class Order
{
    public int Id { get; set; }
    public string UserId { get; set; }
    public decimal TotalAmount { get; set; }
    public DateTime OrderDate { get; set; }
    public string Status { get; set; }
    public List<OrderItem> Items { get; set; }
}

// OrderItem.cs
public class OrderItem
{
    public int Id { get; set; }
    public int OrderId { get; set; }
    public int ProductId { get; set; }
    public int Quantity { get; set; }
    public decimal Price { get; set; }
}

// AppDbContext.cs
public class AppDbContext : DbContext
{
    public DbSet<Product> Products { get; set; }
    public DbSet<Order> Orders { get; set; }
    public DbSet<OrderItem> OrderItems { get; set; }

    public AppDbContext(DbContextOptions<AppDbContext> options) : base(options) { }
}
Enter fullscreen mode Exit fullscreen mode
  1. Backend API

Now, let's create our API controllers:

// ProductsController.cs
[ApiController]
[Route("api/[controller]")]
public class ProductsController : ControllerBase
{
    private readonly AppDbContext _context;

    public ProductsController(AppDbContext context)
    {
        _context = context;
    }

    [HttpGet]
    public async Task<ActionResult<IEnumerable<Product>>> GetProducts()
    {
        return await _context.Products.ToListAsync();
    }

    [HttpGet("{id}")]
    public async Task<ActionResult<Product>> GetProduct(int id)
    {
        var product = await _context.Products.FindAsync(id);
        if (product == null) return NotFound();
        return product;
    }
}

// OrdersController.cs
[ApiController]
[Route("api/[controller]")]
public class OrdersController : ControllerBase
{
    private readonly AppDbContext _context;
    private readonly IPaymentGateway _paymentGateway;

    public OrdersController(AppDbContext context, IPaymentGateway paymentGateway)
    {
        _context = context;
        _paymentGateway = paymentGateway;
    }

    [HttpPost]
    public async Task<ActionResult<Order>> CreateOrder(OrderCreateDto orderDto)
    {
        var order = new Order
        {
            UserId = orderDto.UserId,
            TotalAmount = orderDto.TotalAmount,
            OrderDate = DateTime.UtcNow,
            Status = "Pending",
            Items = orderDto.Items.Select(i => new OrderItem
            {
                ProductId = i.ProductId,
                Quantity = i.Quantity,
                Price = i.Price
            }).ToList()
        };

        _context.Orders.Add(order);
        await _context.SaveChangesAsync();

        return CreatedAtAction(nameof(GetOrder), new { id = order.Id }, order);
    }

    [HttpGet("{id}")]
    public async Task<ActionResult<Order>> GetOrder(int id)
    {
        var order = await _context.Orders.Include(o => o.Items).FirstOrDefaultAsync(o => o.Id == id);
        if (order == null) return NotFound();
        return order;
    }

    [HttpPost("{id}/pay")]
    public async Task<ActionResult> ProcessPayment(int id, PaymentInfoDto paymentInfo)
    {
        var order = await _context.Orders.FindAsync(id);
        if (order == null) return NotFound();

        var paymentResult = await _paymentGateway.ProcessPayment(paymentInfo, order.TotalAmount);

        if (paymentResult.Success)
        {
            order.Status = "Paid";
            await _context.SaveChangesAsync();
            return Ok();
        }
        else
        {
            return BadRequest(paymentResult.ErrorMessage);
        }
    }
}
Enter fullscreen mode Exit fullscreen mode
  1. Frontend Implementation (React.js)

Here's a simplified version of the frontend:

// App.js
import React from 'react';
import { BrowserRouter as Router, Route, Switch } from 'react-router-dom';
import ProductList from './components/ProductList';
import Cart from './components/Cart';
import Checkout from './components/Checkout';

function App() {
  return (
    <Router>
      <Switch>
        <Route exact path="/" component={ProductList} />
        <Route path="/cart" component={Cart} />
        <Route path="/checkout" component={Checkout} />
      </Switch>
    </Router>
  );
}

export default App;

// ProductList.js
import React, { useState, useEffect } from 'react';
import axios from 'axios';

function ProductList() {
  const [products, setProducts] = useState([]);

  useEffect(() => {
    axios.get('/api/products').then(response => setProducts(response.data));
  }, []);

  return (
    <div>
      <h1>Products</h1>
      {products.map(product => (
        <div key={product.id}>
          <h2>{product.name}</h2>
          <p>{product.description}</p>
          <p>Price: ${product.price}</p>
          <button>Add to Cart</button>
        </div>
      ))}
    </div>
  );
}

export default ProductList;

// Checkout.js
import React, { useState } from 'react';
import axios from 'axios';

function Checkout() {
  const [paymentInfo, setPaymentInfo] = useState({
    cardNumber: '',
    expirationDate: '',
    cvv: ''
  });

  const handleSubmit = async (e) => {
    e.preventDefault();
    try {
      const response = await axios.post('/api/orders/1/pay', paymentInfo);
      console.log('Payment successful', response.data);
    } catch (error) {
      console.error('Payment failed', error);
    }
  };

  return (
    <form onSubmit={handleSubmit}>
      <input
        type="text"
        placeholder="Card Number"
        value={paymentInfo.cardNumber}
        onChange={(e) => setPaymentInfo({ ...paymentInfo, cardNumber: e.target.value })}
      />
      <input
        type="text"
        placeholder="Expiration Date"
        value={paymentInfo.expirationDate}
        onChange={(e) => setPaymentInfo({ ...paymentInfo, expirationDate: e.target.value })}
      />
      <input
        type="text"
        placeholder="CVV"
        value={paymentInfo.cvv}
        onChange={(e) => setPaymentInfo({ ...paymentInfo, cvv: e.target.value })}
      />
      <button type="submit">Pay Now</button>
    </form>
  );
}

export default Checkout;
Enter fullscreen mode Exit fullscreen mode
  1. Payment Gateway Integration

We'll create an interface for our payment gateway and a mock implementation:

// IPaymentGateway.cs
public interface IPaymentGateway
{
    Task<PaymentResult> ProcessPayment(PaymentInfoDto paymentInfo, decimal amount);
}

// MockPaymentGateway.cs
public class MockPaymentGateway : IPaymentGateway
{
    public async Task<PaymentResult> ProcessPayment(PaymentInfoDto paymentInfo, decimal amount)
    {
        // Simulate processing delay
        await Task.Delay(1000);

        // Simulate a successful payment 90% of the time
        if (new Random().Next(100) < 90)
        {
            return new PaymentResult { Success = true };
        }
        else
        {
            return new PaymentResult { Success = false, ErrorMessage = "Payment failed" };
        }
    }
}

// PaymentResult.cs
public class PaymentResult
{
    public bool Success { get; set; }
    public string ErrorMessage { get; set; }
}
Enter fullscreen mode Exit fullscreen mode
  1. Order Processing

The order processing flow would look like this:

  1. User adds products to their cart (handled in the frontend).
  2. User proceeds to checkout and enters payment information.
  3. Frontend sends a request to create an order (POST /api/orders).
  4. Backend creates the order and returns the order ID.
  5. Frontend sends payment information along with the order ID (POST /api/orders/{id}/pay).
  6. Backend processes the payment through the payment gateway.
  7. If successful, the order status is updated to "Paid".

To implement this system:

  1. Set up your ASP.NET Core project and configure Entity Framework Core with your database.
  2. Implement the models and DbContext as shown above.
  3. Create the API controllers and implement the endpoints.
  4. Set up your React.js frontend and implement the components.
  5. Integrate a real payment gateway (like Stripe or PayPal) instead of the mock implementation.

Key points to internalize:

  • Separation of concerns: The backend handles data persistence and business logic, while the frontend focuses on user interface and experience.
  • API design: RESTful endpoints for CRUD operations on products and orders.
  • Asynchronous operations: Using async/await for database and API calls to improve performance.
  • Payment flow: Creating an order first, then processing the payment separately.
  • Security: In a real implementation, you'd need to handle authentication, authorization, and secure the payment process (e.g., using HTTPS, tokenization for payment info).

This example provides a basic structure for an e-commerce system. In a production environment, you'd need to add more features like user authentication, inventory management, more complex product structures, and robust error handling. You'd also need to implement proper security measures, especially around payment processing.

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
Terabox Video Player