3 Topics
Chapter•110 Minutes

Design Payments, Orders, and Inventory Systems

Learn to protect correctness in workflows involving money, limited inventory, retries, and external payment providers.

Order and Payment State Machines

Represent order and payment lifecycles explicitly instead of using loosely related booleans. An order might move from PENDING to CONFIRMED, CANCELLED, or FULFILLED; a payment may be CREATED, AUTHORIZED, CAPTURED, FAILED, or REFUNDED. Valid transitions should be enforced and audited.

Do not equate an HTTP success from a payment provider with final settlement unless the provider's contract says so. Webhooks may arrive late, out of order, or more than once. Verify signatures, persist provider event IDs, and process events idempotently. Periodic reconciliation compares internal state with provider records to detect missed callbacks or uncertain outcomes.

Separate order state from payment state because they have related but distinct lifecycles. Define what happens when payment succeeds after an order was cancelled, or when inventory expires before capture completes.

Key Takeaways
  • Model allowed state transitions explicitly.
  • Treat provider webhooks as duplicate and potentially out-of-order events.
  • Use reconciliation to resolve uncertain external outcomes.
Knowledge Check

What prevents two concurrent purchases from both consuming the final unit of stock?

Inventory Reservation and Concurrency Control

If one item remains, two concurrent requests must not both purchase it. A read-then-write sequence without atomic protection can oversell because both requests may read the same available quantity.

Use an atomic conditional update, row-level locking, optimistic concurrency, or a reservation record with uniqueness constraints. For example, decrement inventory only when available >= requestedQuantity; check the affected-row count to determine whether the reservation succeeded.

Reservations need expiry and cleanup, but expiration races with payment confirmation. Use explicit reservation states and version checks so an expired reservation cannot be consumed silently. For high-demand drops, queue admission or per-item serialization may be necessary to protect the inventory store.

Atomic inventory decrement
const result = await Inventory.updateOne(
  { sku, available: { $gte: quantity } },
  { $inc: { available: -quantity } }
);
if (result.modifiedCount !== 1) {
  throw new Error("Insufficient inventory");
}
💡 The predicate and decrement execute as one atomic document update. Validate that quantity is positive, enforce a suitable schema, and use a transaction or reservation model if other records must change atomically.
Key Takeaways
  • Avoid read-then-write inventory checks without concurrency control.
  • Atomic conditional updates can enforce simple stock invariants.
  • Reservation expiry and payment completion require explicit race handling.

Sagas, Idempotency Keys, and Reconciliation

Checkout spans inventory, payment, order management, and notifications, often across different databases and providers. There is usually no single ACID transaction across all of them. Define a workflow with durable steps, timeouts, retries, and compensating actions.

An idempotency key identifies one logical client operation across retries. Store the key, relevant request fingerprint, and outcome with a uniqueness constraint. Reusing a key with a different payload should produce a defined conflict rather than silently returning an unrelated result.

Reconciliation is a first-class safety mechanism. Periodically compare orders, payment provider transactions, refunds, and inventory reservations. Alert on mismatches and resolve them through auditable repair workflows. Reconciliation handles the cases that synchronous code cannot conclusively determine after network failures.

Key Takeaways
  • Use durable workflow state for multi-service checkout.
  • Scope idempotency keys and reject conflicting reuse.
  • Reconciliation repairs uncertainty that retries alone cannot resolve.