Capabilities/Security & Payments

Payment Processing

Idempotent charges, webhook reconciliation, and PCI compliance for online payments

paymentsStripeidempotencyPCIwebhooksfintech

Learning lens

Start with judgment, not a universal prescription.

This page is a learning model for understanding the capability. It does not claim exact production internals, exact costs, or an infinite-scale architecture.

Evidence

Conceptual pattern

0->1 default

Start with explicit trust boundaries, auditable decisions, and managed primitives where correctness matters more than novelty.

Cost drivers

audit retentionencryption and key managementpolicy checkscompliance evidence

Watch for breakpoints

  • -authorization logic spreads across services
  • -audit queries become operationally important
  • -customers require stronger controls

Learn first

Concepts behind this architecture

The Problem

Accepting online payments is one of the highest-stakes features in software. A bug can charge customers twice, lose money, or create compliance violations. Payment processing requires integrating with payment gateways (Stripe, Adyen, Braintree), handling asynchronous payment flows (3D Secure, bank transfers), ensuring idempotency (never charge twice for the same operation), reconciling payments via webhooks, managing subscriptions and refunds, and maintaining PCI DSS compliance to protect card data. The system must be auditable, resilient to failures at any point in the flow, and eventually consistent between your database and the payment provider.

Architectural Approaches

Payment Gateway Integration (Stripe, Adyen)

Integrate directly with a payment gateway API. Your server creates payment intents, the client collects card details via the gateway’s embedded UI (Stripe Elements, Adyen Drop-in), and the gateway handles the actual charge. You never see raw card numbers, simplifying PCI compliance to SAQ-A level.

Pros

  • +PCI scope is minimized — card data never touches your servers
  • +Mature SDKs handle edge cases (3D Secure, retries, currency conversion)
  • +Built-in fraud detection and risk scoring
  • +Comprehensive dashboard for payment operations

Cons

  • −Per-transaction fees (2.9% + $0.30 typical for Stripe)
  • −Vendor dependency for a critical business function
  • −Complex webhook integration for async payment events
  • −Each gateway has its own API patterns and quirks

Payment Orchestration Layer

Build an abstraction layer that routes payments to multiple gateways based on rules (lowest fee, highest success rate, currency, region). Services like Primer or custom-built orchestrators provide gateway-agnostic payment processing with automatic failover.

Pros

  • +Multi-gateway redundancy — failover if one gateway is down
  • +Optimize for lowest fees per transaction
  • +A/B test gateways for conversion rate optimization
  • +Single API for your application regardless of gateway

Cons

  • −Additional complexity layer
  • −Must maintain integrations with multiple gateways
  • −Reconciliation across gateways is harder
  • −Adds latency from the orchestration hop

Ledger-Based Architecture

Model all financial operations as double-entry ledger entries. Every payment, refund, fee, and payout is recorded as a pair of debit/credit entries in an immutable ledger. The ledger is the source of truth; the payment gateway is an external system reconciled against the ledger.

Pros

  • +Complete audit trail — every cent is accounted for
  • +Easy reconciliation — compare ledger with gateway reports
  • +Supports complex financial operations (partial refunds, credits, splits)
  • +Foundation for financial reporting and compliance

Cons

  • −More complex to implement than simple payment tracking
  • −Requires understanding of double-entry bookkeeping
  • −Ledger entries are immutable — corrections require compensating entries
  • −Overkill for simple e-commerce (single product, no marketplace)

Architecture

Loading diagram...
Payment Processing — High-level architecture

Key Components

Payment API

REST endpoints for creating payments, processing refunds, and managing subscriptions. Accepts tokenized payment methods (never raw card numbers). Validates amounts, currencies, and business rules before calling the gateway. Returns payment status and handles async confirmations.

Idempotency Layer

Ensures that retrying a payment request doesn’t create duplicate charges. Uses an idempotency key (client-generated UUID) stored in Redis/database. If the same key is seen again, return the cached result instead of processing a new payment. Critical for handling network failures and retries.

Ledger Service

Maintains a double-entry ledger recording every financial transaction. Each payment creates entries: debit customer account, credit revenue account. Refunds reverse the entries. The ledger balance must always equal zero (balanced books). Provides the source of truth for financial reporting.

Webhook Handler

Receives and processes payment events from the gateway (payment_intent.succeeded, charge.refunded, invoice.paid). Verifies webhook signatures, deduplicates events, and updates the ledger and order status. Must be idempotent — the same event may be delivered multiple times.

Reconciliation Service

Periodically compares your ledger with the gateway’s records (via API or settlement reports). Identifies discrepancies (missing payments, unmatched refunds, fee differences). Alerts on mismatches for manual investigation. Runs daily for operational reconciliation and monthly for accounting close.

Fraud Detection

Evaluates payment risk before processing. Checks velocity (too many attempts from one IP), amount anomalies, device fingerprinting, and address verification (AVS). Can block suspicious payments or require additional verification (3D Secure step-up). Integrates with Stripe Radar or custom ML models.

Data Model

Loading diagram...
Payment Processing — Entity relationship diagram

Idempotency in Payment Processing

Double-charging a customer is the worst bug in payment processing. Idempotency prevents it.

How it works:

  1. Client generates a unique idempotency key (UUID v4) for each payment attempt
  2. Client sends: POST /payments with header Idempotency-Key: abc-123
  3. Server checks if key exists in the idempotency store
  4. If found: return the cached response (same status, same payment ID)
  5. If not found: process the payment, store the result keyed by the idempotency key

Storage: Redis with 24-48 hour TTL is ideal. Store the full response (status code + body) so retries return identical responses.

Race condition: Two requests with the same key arrive simultaneously. Use Redis SETNX (set-if-not-exists) as a distributed lock. The first request wins and processes; the second waits and returns the cached result.

Stripe’s approach: Stripe accepts an Idempotency-Key header on all POST requests. Results are cached for 24 hours. If the same key is sent with different parameters, Stripe returns a 400 error — the key is tied to the original request parameters.

Critical rule: The idempotency key must be generated by the client, not the server. If the server generates it, a network failure between server and client means the client can’t retry with the same key.

Webhook-Driven Payment State Machine

Payments are inherently asynchronous. A credit card charge may go through 3D Secure, bank verification, and fraud checks before succeeding or failing. Model payments as a state machine driven by gateway webhooks.

Payment states: created → processing → requires_action → succeeded → (refunded)

Webhook events (Stripe example):

  • payment_intent.created → set status to “processing”
  • payment_intent.requires_action → redirect user to 3D Secure
  • payment_intent.succeeded → fulfill order, update ledger
  • payment_intent.payment_failed → notify customer, allow retry
  • charge.refunded → update ledger, notify customer

Reliability rules:

  1. Process webhooks idempotently — Stripe may send the same event multiple times. Use the event ID for deduplication.
  2. Verify webhook signatures — Stripe signs webhooks with HMAC. Verify before processing.
  3. Return 200 quickly — Process the webhook asynchronously (enqueue and ack). Stripe retries if you don’t respond within 20 seconds.
  4. Don’t rely solely on webhooks — Use webhooks as the primary signal but also poll the payment status API as a backup. Belt and suspenders.
  5. Handle out-of-order events — A “succeeded” event may arrive before a “processing” event. Check the current state before applying transitions.

PCI Compliance Strategy

PCI DSS (Payment Card Industry Data Security Standard) has strict requirements for handling card data. Minimizing your PCI scope saves months of compliance work.

SAQ-A (minimal scope): Use hosted payment fields (Stripe Elements, Adyen Drop-in). Card numbers are entered in an iframe served by the gateway. Your servers never see card data. Easiest compliance — a self-assessment questionnaire.

SAQ A-EP: Your server serves the payment page but card data is submitted directly to the gateway (JavaScript tokenization). More scope than SAQ-A but less than full PCI.

Full PCI DSS: If you handle raw card numbers (e.g., call center, legacy integration), you need full compliance: network segmentation, encryption, access controls, penetration testing, annual audits. Extremely expensive and time-consuming.

Best practice: Always use SAQ-A. Never let card data touch your infrastructure.

Token vault: If you need to store payment methods for recurring billing, use the gateway’s token vault. Stripe stores the card and gives you a payment method ID (pm_xxx). You store only the ID, not the card number.

Logging: Never log card numbers, CVVs, or full card details. If you accidentally log them (stack traces, request logging), you’ve expanded your PCI scope. Use middleware to redact sensitive fields from logs.

Real-World Examples

Stripe

The most developer-friendly payment gateway. Payment Intents API handles the full payment lifecycle including 3D Secure. Idempotency keys on all endpoints. Comprehensive webhook system. Stripe Elements for PCI-compliant card collection. Stripe Radar for ML-based fraud detection.

Shopify

Payment orchestration supporting 100+ payment providers via Shopify Payments (powered by Stripe) and third-party gateways. Double-entry ledger for merchant balances. Handles multi-currency, tax calculation, and marketplace payouts.

Uber

Real-time payment processing for millions of rides daily. Pre-authorization at ride start, final charge at ride end. Supports multiple payment methods per user with fallback ordering. Custom fraud detection for rider and driver accounts.

Square

Unified commerce platform handling in-person (POS terminals) and online payments. Card-present transactions use EMV chip for security. Online payments use a hosted payment form. Provides hardware (readers) and software (SDK) for omnichannel payment processing.

Architectural Tradeoffs

Single gateway vs multi-gateway orchestration

Pros

  • +Single: simpler integration, one dashboard, one set of webhooks
  • +Multi: redundancy, lower fees through smart routing
  • +Single: faster to implement, easier reconciliation

Cons

  • −Single: vendor dependency, no failover
  • −Multi: complex reconciliation, more code to maintain
  • −Multi: split data across dashboards, harder to debug issues

Synchronous payment confirmation vs webhook-driven

Pros

  • +Synchronous: simpler code, immediate result
  • +Webhook: handles async flows (3D Secure, bank transfers)
  • +Webhook: more reliable — server-to-server, retried on failure

Cons

  • −Synchronous: doesn't work for all payment methods
  • −Webhook: eventual consistency, more complex state management
  • −Both: use synchronous for instant payments, webhooks as confirmation

Simple payment tracking vs double-entry ledger

Pros

  • +Simple: faster to build, sufficient for basic e-commerce
  • +Ledger: complete audit trail, easy reconciliation
  • +Ledger: supports complex operations (marketplace splits, credits)

Cons

  • −Simple: hard to reconcile, no formal audit trail
  • −Ledger: more complex, requires accounting knowledge
  • −Ledger: overkill for simple single-product stores

Learn Payment Processing

Copy a learning context prompt for an AI assistant. It keeps assumptions visible and asks for tradeoffs, cost drivers, failure modes, and what to measure before adding complexity.

Explore More Capabilities