Order Fulfillment System Low-Level Design

What is Order Fulfillment?

Order fulfillment covers the steps from a confirmed order to the item delivered to the customer: pick → pack → ship → track → deliver. The fulfillment system coordinates warehouse management, carrier integration, shipping label generation, and real-time tracking updates. A well-designed fulfillment system directly impacts customer experience (delivery speed, accuracy) and operational cost.

Requirements

  • Route orders to the optimal warehouse (closest to destination, has stock)
  • Generate pick lists for warehouse workers
  • Print shipping labels and submit to carrier APIs (UPS, FedEx, USPS)
  • Track shipments in real time; push updates to customers
  • Handle returns and re-shipments
  • 100K orders/day, SLA: ship within 24h of order placement

Order Lifecycle

PLACED → PAYMENT_CONFIRMED → ROUTED → PICKING → PACKED → SHIPPED → IN_TRANSIT
→ OUT_FOR_DELIVERY → DELIVERED
                     ↓
              EXCEPTION (delay, lost, damage)
                     ↓
              RETURN_REQUESTED → RETURN_RECEIVED → REFUNDED

Warehouse Routing

When an order is confirmed, route to the best warehouse. Routing algorithm:

  1. Find warehouses with all order items in stock (JOIN Inventory WHERE quantity_available >= quantity)
  2. Calculate estimated shipping time from each candidate warehouse to the delivery address (carrier API or shipping zone table)
  3. Calculate shipping cost for each candidate (carrier rate table: weight × zone × service)
  4. Score = alpha * delivery_time + beta * shipping_cost (configurable weights)
  5. Assign to the warehouse with the best score
  6. Reserve inventory at that warehouse

Split shipments: if no single warehouse has all items, split across two warehouses. Minimize splits (customer receives everything in one delivery when possible).

Pick List Generation

A pick list tells warehouse workers which items to retrieve. Generated when the order is assigned to a warehouse:

PickList(pick_list_id, order_id, warehouse_id, status ENUM(PENDING,IN_PROGRESS,COMPLETE),
         created_at, assigned_to, completed_at)

PickListItem(pick_list_id, sku, location_code, quantity, picked_quantity, scanned_at)
-- location_code = aisle-rack-bin, e.g., "B3-12-04"

Batch picking: group multiple orders’ items by warehouse zone to minimize travel distance. A picker walks once through the warehouse collecting items for 10-20 orders simultaneously. Zone picking: divide warehouse into zones; each picker is responsible for one zone. Items are merged at the packing station.

Carrier Integration and Label Generation

def create_shipment(order_id, warehouse_id):
    order = get_order(order_id)
    package = calculate_package(order.items)  # weight, dimensions

    # Call carrier API (EasyPost, ShipStation, or direct UPS/FedEx API)
    response = carrier_api.create_shipment(
        from_address=warehouse.address,
        to_address=order.shipping_address,
        parcel={'weight_oz': package.weight_oz,
                'length': package.length, ...},
        service='UPS_GROUND'
    )

    label_url = response.postage_label.label_url
    tracking_number = response.tracking_code
    rate = response.rate.rate  # cost in dollars

    UPDATE Order SET tracking_number=tracking_number, status='SHIPPED',
                     carrier='UPS', label_url=label_url, shipped_at=NOW()

Shipment Tracking

Carriers provide tracking webhooks (or polling APIs) with status updates: picked up, in transit, out for delivery, delivered, exception. Consume tracking events via webhook → Kafka → update Order status and notify customer. Push notification when out for delivery and when delivered. For tracking page: query order.tracking_number → carrier tracking API (cached in Redis, TTL=5min). Exception handling: if a package is stuck in transit for > 2× expected delivery time, alert customer service team and initiate a trace with the carrier.

Returns

Return flow: customer requests return → generate return shipping label (carrier API) → email label to customer → customer ships back → warehouse receives and inspects → if condition OK: restock inventory; if damaged: write off → issue refund. Track return: ReturnRequest(order_id, reason, status ENUM(REQUESTED,LABEL_SENT,IN_TRANSIT,RECEIVED,INSPECTED,REFUNDED)). Restock only if item is resellable (no damage, original packaging). Disposition code on inspection: RESTOCK, DISPOSE, VENDOR_RETURN.

Key Design Decisions

  • Warehouse routing algorithm — minimize shipping time and cost with configurable weights
  • Batch picking — reduces warehouse travel time, increases throughput per shift
  • EasyPost/ShipStation for carrier abstraction — single API for all carriers, automatic rate shopping
  • Carrier webhook for tracking — real-time updates without polling
  • State machine for order lifecycle — prevents invalid state transitions

Amazon system design is the canonical order fulfillment interview topic. See common questions for Amazon interview: order fulfillment and warehouse system design.

Shopify system design covers order fulfillment and shipping. Review patterns for Shopify interview: order fulfillment system design.

Uber Eats system design covers order fulfillment and delivery logistics. See design patterns for Uber interview: order fulfillment and logistics design.

Scroll to Top