Create order

Order creation flow: from the frontend to the orders microservice, with event publishing and coordination with inventory and payments.

Why order creation is a complex flow

Creating an order is not simply saving a record to a database. It’s a flow that involves multiple services, business validations, inventory reservation, payment initiation, and notifications. It’s the perfect example of how synchronous and asynchronous communication coexist within a single use case.

The complete flow

sequenceDiagram
    participant FE as Frontend
    participant GW as API Gateway
    participant BFF as BFF
    participant ORD as ms-orders
    participant DB as Orders DB
    participant EB as Event Bus
    participant INV as ms-inventory
    participant PAY as ms-payments
    participant NOT as ms-notifications

    FE->>GW: POST /orders
    GW->>GW: Auth, rate limiting
    GW->>BFF: Forward
    BFF->>ORD: Crear orden

    ORD->>ORD: Validar datos de la orden
    ORD->>DB: Guardar orden (estado: pending)
    DB-->>ORD: OK
    ORD->>EB: Publicar OrderPlaced

    ORD-->>BFF: Orden creada (id, estado)
    BFF-->>GW: Respuesta para UI
    GW-->>FE: 201 Created + orden

    Note over EB: Procesamiento asíncrono

    EB->>INV: OrderPlaced
    INV->>INV: Reservar stock
    INV->>EB: InventoryReserved

    EB->>PAY: OrderPlaced
    PAY->>PAY: Iniciar proceso de pago

    EB->>NOT: OrderPlaced
    NOT->>NOT: Enviar confirmación al usuario

Synchronous phase: creating the order

The first part of the flow is synchronous. The user is waiting for confirmation that their order was received.

Frontend

  1. The user reviews their cart and confirms the purchase
  2. The frontend sends the order data: items, quantities, shipping address, payment method
  3. It shows a spinner while waiting for confirmation
  4. It receives the confirmation with the order ID and displays a success message

BFF

  1. Receives the data from the frontend
  2. Can enrich the request (resolve product IDs, validate format)
  3. Invokes the orders microservice
  4. Transforms the response for the frontend

Orders microservice (ms-orders)

This is the service that orchestrates the creation:

  1. Validates the order data (items exist, quantities valid, address complete)
  2. Calculates the total
  3. Saves the order to its database with status pending
  4. Publishes the OrderPlaced event to the Event Bus
  5. Returns the created order to the BFF

Key point: the order is saved and the event is published in the same operation (ideally using the Outbox Pattern to guarantee consistency).

Asynchronous phase: coordination between services

Once the OrderPlaced event is published, several services react independently.

Inventory (ms-inventory)

  1. Receives the OrderPlaced event
  2. Verifies there is enough stock for each item
  3. Reserves the stock (marks it as committed)
  4. Publishes InventoryReserved or InventoryInsufficient

Payments (ms-payments)

  1. Receives the OrderPlaced event
  2. Starts the charging process with the payment provider
  3. Publishes PaymentCompleted or PaymentFailed

Notifications (ms-notifications)

  1. Receives the OrderPlaced event
  2. Sends a confirmation email to the user
  3. Can send a push notification if the app supports it

Coordination and order states

The order goes through several states depending on the events it receives:

stateDiagram-v2
    [*] --> Pending: OrderPlaced
    Pending --> Confirmed: InventoryReserved + PaymentCompleted
    Pending --> Cancelled: InventoryInsufficient
    Pending --> Cancelled: PaymentFailed
    Confirmed --> Shipped: ShipmentCreated
    Shipped --> Delivered: ShipmentDelivered
    Cancelled --> [*]
    Delivered --> [*]

The orders microservice listens to the inventory and payment events to update the state:

  • If both are successful → confirmed
  • If inventory fails → cancelled (and the payment is reverted if it was already charged)
  • If payment fails → cancelled (and the reserved inventory is released)

The consistency problem

In this flow, there is no distributed transaction guaranteeing that everything happens atomically. Instead, eventual consistency is used:

  1. The order is created in pending status
  2. The services process their parts independently
  3. The result events update the order’s state
  4. If something fails, compensations are executed (release stock, revert payment)

This is the Saga pattern in action: a sequence of local transactions coordinated by events.

Compensations

When something fails after other services have already acted, compensations are needed:

FailureCompensation
Payment fails after reserving inventoryPublish PaymentFailed → inventory releases stock
Insufficient inventory after starting paymentPublish InventoryInsufficient → payments cancels the charge
Timeout with no response from inventoryOrder moves to cancelled after a time limit

Idempotency

Each consumer must be idempotent. If the OrderPlaced event is delivered twice:

  • Inventory must not reserve stock twice
  • Payments must not charge twice
  • Notifications must not send two emails

The most common way to achieve this is to store the ID of the processed event and check it before acting.

What the user sees

From the user’s perspective:

  1. They click “Confirm purchase”
  2. They see a spinner for 1–2 seconds
  3. They see “Order #12345 received” with status “Processing”
  4. They receive a confirmation email
  5. They can check the order status, which updates as the services process it

The user doesn’t need to know that behind the scenes there are 4 services coordinating. They just see a clean flow.

Summary

Creating an order combines synchronous communication (to give the user a fast response) with asynchronous communication (to coordinate inventory, payments, and notifications). Consistency is achieved through events and compensations, not through distributed transactions. Each service is responsible for its part and reacts to the events of the others.