Acme Inc
Discover, Explore and Document your Event Driven Architectures.
This reference is generated from the Acme Inc EventCatalog. It documents 10 domains, 18 systems and 32 services, the 71 messages they exchange (45 events, 20 commands and 6 queries), 8 channels, 15 data stores, 7 flows and 29 entities and the 8 teams that own them.
Everything links to everything else. Press ⌘K to jump to any resource.
- Domains
- 10
- Systems
- 18
- Services
- 32
- Events
- 45
- Commands
- 20
- Queries
- 6
- Channels
- 8
- Data stores
- 15
- Flows
- 7
- Teams
- 8
npx eventcatalog buildDomains
Business areas and the services and messages that belong to them.
Catalog
v1.0.0Core domainBusiness CriticalThe Catalog domain owns everything about products — how they are created, maintained and made discoverable across Acme Inc. It is the source of truth for product data and powers product search across the business.
A single item Acme Inc sells, with a name, price, category and lifecycle status.
Stock Keeping Unit — the unique, human-meaningful code that identifies a product.
The complete, authoritative collection of products Acme Inc offers.
A denormalised, search-optimised copy of the catalog that powers product search.
Where a product sits in its life: DRAFT, ACTIVE or ARCHIVED.
A table where product changes are recorded in the same transaction, then published as events.
Overview
The Catalog domain is responsible for the lifecycle of every product Acme Inc sells, and for making those products discoverable. It is split into two internal systems that work together:
How the systems work together
The Product Catalog System is the authoritative source of product data. Whenever a product is created, updated or deleted it publishes a domain event. The Search System subscribes to those events, keeps its search index in sync, and exposes a search API so other teams never have to query the catalog database directly.
Value Chain
A Wardley map of the Catalog domain. Product search is where we differentiate, so it sits closest to the shopper and furthest from commodity. The data stores and compute underneath are bought, not built.
wardley-beta
title Catalog value chain
anchor Shopper [0.96, 0.66]
anchor Merchant [0.96, 0.34]
component Product Search [0.84, 0.60]
component Product Catalog [0.76, 0.42]
component Search Index [0.60, 0.58]
component Product Data Model [0.60, 0.30]
component Event Bus [0.44, 0.74]
component Search Engine [0.34, 0.78]
component Catalog Database [0.24, 0.86]
component Cloud Compute [0.10, 0.94]
Shopper -> Product Search
Merchant -> Product Catalog
Product Search -> Search Index
Product Catalog -> Product Data Model
Product Catalog -> Event Bus
Search Index -> Event Bus
Search Index -> Search Engine
Product Catalog -> Catalog Database
Search Engine -> Cloud Compute
Catalog Database -> Cloud Compute
evolve Search Engine 0.90
evolve Product Data Model 0.48
note "Search relevance is our differentiator, keep it custom" [0.90, 0.40]
note "Move self hosted search to a managed service" [0.28, 0.52]Architecture Graph
Where Catalog sits in the wider architecture — its systems and messages, and the neighbouring domains it talks to.
The diagram below shows the domain's systems, how they relate, and the people who interact with them.
Customer
v1.0.0Core domainBusiness CriticalThe Customer domain owns who our customers are — how they register, how their profile is maintained, and how they are authenticated across Acme Inc. It is the source of truth for customer identity and profile data.
A person with an account at Acme Inc, identified by a unique customer id and email.
The credentials and login information used to prove a customer is who they say they are.
Verifying that a sign-in attempt belongs to a real customer.
A secret (such as a password) a customer uses to authenticate. Never stored in plain text.
Where a customer account sits: ACTIVE, SUSPENDED or CLOSED.
The authoritative store of customer credentials and login identities.
Overview
The Customer domain is responsible for the lifecycle of every customer account at Acme Inc — registration, profile updates, and authentication. It is split into two systems:
How the systems work together
The Customer Management System owns customer profile data — it accepts registration and update commands and publishes events when customers change. The Identity Provider handles authentication: it verifies credentials and emits an event when a customer successfully authenticates, which the rest of the business can react to.
Subdomains
The Customer domain also contains two subdomains: Loyalty awards and reverses loyalty points as orders complete or are cancelled, and Customer Notifications keeps customers informed by email, SMS and push in response to events from across Acme Inc.
System Diagram
The systems in this domain, how they relate, and the people who interact with them.
Customer Notifications
v1.0.0Generic subdomainThe Customer Notifications subdomain keeps customers informed. It listens to key moments across Ordering, Fulfilment, Payments, Reviews, Loyalty and Returns and sends the customer an email, SMS or push notification on their preferred channel.
Overview
The Customer Notifications subdomain is part of the Customer domain. It has no systems of its own — a single Notification Service consumes events from across the business and notifies customers according to their Notification Preferences.
| Source domain | Events |
|---|---|
| Ordering | Order Confirmed |
| Fulfilment | Shipment Delivered, Return Approved |
| Payments | Payment Failed, Refund Processed |
| Reviews | Review Published |
| Customer (Loyalty) | Loyalty Points Earned |
Fulfilment
v1.0.0Core domainBusiness CriticalThe Fulfilment domain gets a confirmed order to the customer. It reserves stock, picks and packs orders in the warehouse, and hands them to carriers for delivery.
Everything that gets a confirmed order physically to the customer — stock, packing and shipping.
The quantity of a product physically available to sell.
A temporary hold on stock for a specific order, taken during checkout.
Collecting an order's items from the warehouse shelves.
Boxing up a picked order into one or more parcels ready for shipping.
A packed order handed to a carrier for delivery, tracked from dispatch to delivery.
The external delivery company that transports shipments to customers.
A code from the carrier that lets the customer follow a shipment's progress.
Overview
The Fulfilment domain is responsible for the physical side of an order — making sure stock is available, picking and packing it, and shipping it to the customer. It owns three internal systems and integrates with external carriers:
How the systems work together
When an order is completed, the Warehouse System picks and packs it, having relied on the Inventory System to reserve stock earlier in checkout. Once packed, the Shipping System creates a shipment with an external Carrier, which delivers it to the customer and reports progress back.
Subdomains
The Returns subdomain handles the reverse journey — accepting return requests, approving them, and confirming when items arrive back so Payments can refund the customer and Inventory can restock.
Value Chain
A Wardley map of the Fulfilment domain. Delivery is the promise customers see, carriers are a commodity we rent, and warehouse automation is the most novel part of the chain.
wardley-beta
title Fulfilment value chain
anchor Customer [0.96, 0.62]
component Delivery Promise [0.86, 0.50]
component Stock Reservation [0.72, 0.46]
component Pick and Pack [0.64, 0.34]
component Shipment Booking [0.56, 0.60]
component Warehouse Automation [0.36, 0.22]
component Carrier Network [0.40, 0.88]
component Inventory Database [0.26, 0.86]
component Cloud Compute [0.10, 0.94]
Customer -> Delivery Promise
Delivery Promise -> Stock Reservation
Delivery Promise -> Shipment Booking
Stock Reservation -> Inventory Database
Shipment Booking -> Pick and Pack
Shipment Booking -> Carrier Network
Pick and Pack -> Warehouse Automation
Inventory Database -> Cloud Compute
evolve Warehouse Automation 0.52
evolve Shipment Booking 0.82
note "Robotic picking pilot in the main warehouse" [0.30, 0.06]
note "Consolidate carriers behind a multi carrier aggregator" [0.50, 0.70]System Diagram
The systems in this domain, how they relate, and the people who interact with them.
Loyalty
v1.0.0Supporting subdomainThe Loyalty subdomain rewards customers for shopping with Acme Inc. It awards points when orders complete, reverses them when orders are cancelled, and keeps each customer's points balance.
Overview
The Loyalty subdomain is part of the Customer domain. It listens to the order lifecycle from the Ordering domain and turns completed orders into loyalty points that customers can redeem on future purchases.
| Trigger | Outcome |
|---|---|
| Order Completed | Points are awarded and Loyalty Points Earned is published. |
| Order Cancelled | Previously awarded points are removed and Loyalty Points Reversed is published. |
Ordering
v1.0.0Core domainBusiness CriticalThe Ordering domain turns a checked-out cart into a confirmed order. It orchestrates checkout — reserving inventory, authorizing payment and creating the order — and owns the lifecycle of every order.
A confirmed intent to purchase, created from a checked-out cart and owned for its whole lifecycle.
The flow that turns a checked-out cart into a confirmed order.
A multi-step process with compensating actions, used to coordinate checkout across systems.
A temporary hold on stock for the items in a cart, taken during checkout.
A hold placed on a customer's payment method for the order total, captured when the order is created.
A single product line within an order: a product, a quantity and the price paid per unit.
Where an order sits in its life: CREATED, COMPLETED or CANCELLED.
Overview
The Ordering domain is responsible for everything that happens once a customer commits to buy — from the moment their cart is checked out to a confirmed, fulfilled order. It is split into two systems:
How the systems work together
When the Shopping domain checks out a cart, the Checkout System takes over. It orchestrates the steps needed to place an order — reserving inventory, authorizing payment, and finally asking the Order Management System to create the order. The Order Management System then owns that order for the rest of its life, publishing events as it is created, completed or cancelled.
Value Chain
A Wardley map of the Ordering domain. Placing an order is the most visible need in the business, the checkout orchestration behind it is custom, and the workflow tooling it runs on is evolving towards a product.
wardley-beta
title Ordering value chain
anchor Customer [0.96, 0.56]
component Place Order [0.88, 0.52]
component Checkout Orchestration [0.76, 0.40]
component Order Management [0.66, 0.52]
component Inventory Reservation [0.54, 0.50]
component Payment Authorization [0.54, 0.64]
component Workflow Engine [0.38, 0.46]
component Event Bus [0.40, 0.76]
component Order Database [0.24, 0.86]
component Cloud Compute [0.10, 0.94]
Customer -> Place Order
Place Order -> Checkout Orchestration
Checkout Orchestration -> Inventory Reservation
Checkout Orchestration -> Payment Authorization
Checkout Orchestration -> Order Management
Checkout Orchestration -> Workflow Engine
Order Management -> Event Bus
Order Management -> Order Database
Workflow Engine -> Cloud Compute
Order Database -> Cloud Compute
evolve Workflow Engine 0.74
note "Replace bespoke saga code with a managed workflow engine" [0.32, 0.24]System Diagram
The systems in this domain, how they relate, and the people who interact with them.
Resource Diagram
The components that make up this domain.
Architecture Graph
Where Ordering sits in the wider architecture — its systems and messages, and the neighbouring domains it talks to.
Payments
v1.0.0Core domainBusiness CriticalThe Payments domain takes payment for orders and processes refunds. It orchestrates authorization and capture through an external payment processor, and screens payments for fraud.
A charge taken from a customer to pay for an order.
A hold placed on a customer's payment method, confirming funds are available before capture.
Taking the held funds from an authorized payment — turning an authorization into an actual charge.
Returning money to a customer for a previous payment, in full or in part.
The external provider (Stripe) that charges cards and issues refunds on Acme Inc's behalf.
Checking a payment for signs of fraud before allowing the charge to proceed.
A callback the payment processor sends to report the outcome of a charge or refund.
Overview
The Payments domain is responsible for moving money. It authorizes and captures payment for orders, issues refunds, and screens payments for fraud. It owns one internal system and integrates with two external providers:
How the systems work together
The Payment Processing System is the internal orchestrator. When the Ordering domain authorizes a payment, it requests payment via the external Stripe system and, in parallel, asks Fraud Detection to screen the payment. Stripe reports back whether the payment succeeded or failed, and the Payment Processing System records the outcome.
Value Chain
A Wardley map of the Payments domain. Card processing and fraud screening are commodities we buy from providers, so the value we add is in orchestration, refunds and the compliance posture around them.
wardley-beta
title Payments value chain
anchor Shopper [0.96, 0.60]
anchor Finance Team [0.96, 0.30]
component Pay for Order [0.86, 0.58]
component Refund Order [0.80, 0.34]
component Payment Orchestration [0.70, 0.44]
component Fraud Screening [0.56, 0.64]
component Card Processing [0.46, 0.86]
component PCI Compliance [0.38, 0.72]
component Payment Ledger [0.26, 0.60]
component Cloud Compute [0.10, 0.94]
Shopper -> Pay for Order
Finance Team -> Refund Order
Pay for Order -> Payment Orchestration
Refund Order -> Payment Orchestration
Payment Orchestration -> Fraud Screening
Payment Orchestration -> Card Processing
Payment Orchestration -> Payment Ledger
Card Processing -> PCI Compliance
Payment Ledger -> Cloud Compute
evolve Fraud Screening 0.82
evolve Payment Ledger 0.80
note "In house rules engine is being replaced by a managed fraud provider" [0.62, 0.30]
note "Ledger moving to a hosted double entry service" [0.20, 0.36]System Diagram
The systems in this domain, how they relate, and the people who interact with them.
Architecture Graph
Where Payments sits in the wider architecture — its systems and messages, and the neighbouring domains it talks to.
Returns
v1.0.0Supporting subdomainThe Returns subdomain handles items customers send back. It accepts return requests, approves them against the returns policy, and confirms when returned items arrive at the warehouse so they can be refunded and restocked.
Overview
The Returns subdomain is part of the Fulfilment domain and runs the reverse logistics journey through the Returns System.
- A customer sends Request Return and the Returns API publishes Return Requested.
- The Returns Processor checks the returns policy and publishes Return Approved.
- When the parcel reaches the warehouse it publishes Return Received — Payments refunds the customer and Inventory restocks the items.
Reviews & Ratings
v1.0.0Supporting domainThe Reviews & Ratings domain owns customer feedback on products — how reviews are submitted, moderated, published and aggregated into the star ratings shown across the storefront.
Overview
The Reviews & Ratings domain is responsible for everything to do with customer feedback on products: accepting reviews, moderating them for quality and abuse, publishing the approved ones, and aggregating them into the star ratings shown across the storefront.
Unlike most other domains in the catalog, Reviews & Ratings is modelled without systems — its services, data stores and flows hang directly off the domain.
What's inside
| Component | Type | Responsibility |
|---|---|---|
| Review API | Service | Accepts review submissions and serves product reviews. |
| Review Moderation Worker | Service | Screens submitted reviews and publishes or rejects them. |
| Rating Aggregator | Service | Keeps each product's aggregate rating in sync as reviews are published. |
| Review Database | Data Store | System of record for reviews and their moderation state. |
| Rating Cache | Data Store | Fast read store for aggregate product ratings. |
| Review | Entity | The core review aggregate. |
The diagram below shows the services, data stores and messages that make up this domain.
How it works
- A customer submits a review via the Review API, which stores it and publishes Review Submitted.
- The Review Moderation Worker screens the review and publishes either Review Published or Review Rejected.
- The Rating Aggregator consumes Review Published and updates the product's aggregate rating, publishing Rating Updated.
Once a review is live, customers can interact with it: Vote Review Helpful updates its helpful count (publishing Review Helpful Voted), and Flag Review reports it for re-moderation (publishing Review Flagged, which the Review Moderation Worker re-screens).
Shopping
v1.0.0Core domainBusiness CriticalThe Shopping domain owns the customer's path to purchase — building a cart, applying promotions, and checking out. It coordinates the cart and the discounts that apply to it.
A customer's in-progress collection of items they intend to buy.
A single product line within a cart: a product, a quantity and a unit price.
The act of finalising a cart — pricing it and committing to purchase.
A rule that reduces the price of a cart, such as a percentage off or a fixed amount.
The actual amount taken off a specific cart after evaluating the applicable promotions.
The total value of a cart's items before any discounts are applied.
A code a customer enters at checkout to apply a specific promotion.
Overview
The Shopping domain is responsible for everything between browsing and buying — the shopping cart and the promotions applied to it. It is split into two systems:
How the systems work together
The Cart System owns the customer's cart and the checkout flow. When pricing a cart, it asks the Promotion System to calculate the discounts that apply. When the customer checks out, the Cart System publishes an event the rest of the business reacts to.
System Diagram
The systems in this domain, how they relate, and the people who interact with them.
Systems
Groups of services that are built, deployed and owned together.
Carrier
Externalv1.0.0ExternalExternal carrier that delivers shipments to customers. It accepts shipment requests and reports delivery progress back.
delivers shipments for
Overview
The Carrier is the external delivery company Acme Inc uses to ship orders to customers. It is owned and operated by a third party — modelled here as an external system so the catalog shows how the Shipping System integrates with it.
It receives Create Shipment and reports progress back via Shipment Created, Shipment Delivered and Shipment Failed.
Context Diagram
How this system relates to the other systems around it.
Resource Diagram
The services and messages that make up this system.
What's inside
| Component | Type | Responsibility |
|---|---|---|
| Shipping API | Service | Accepts shipment requests and dispatches parcels. |
| Tracking API | Service | Reports delivery progress back to Acme Inc. |
Messages this system publishes
- Shipment Created — a shipment has been created and dispatched.
- Shipment Delivered — a shipment was delivered to the customer.
- Shipment Failed — a shipment could not be delivered.
Cart System
v1.0.0InternalInternal system that owns the customer's shopping cart and the checkout flow. It is the source of truth for cart contents and publishes an event when a cart is checked out.
calculates discounts via
Uses the system. adds items and checks out
Overview
The Cart System owns the shopping cart at Acme Inc. It accepts commands to add and remove items and to check out, persists cart contents in the Cart Database, and asks the Promotion System to calculate the discounts that apply. When a cart is checked out it publishes a Cart Checked Out event.
Context Diagram
How this system relates to the other systems around it.
Resource Diagram
The services, data stores and messages that make up this system.
What's inside
| Component | Type | Responsibility |
|---|---|---|
| Cart API | Service | Public-facing API. Handles add/remove/checkout commands and publishes the checkout event. |
| Cart Database | Data store | PostgreSQL system of record for shopping carts and their items. |
Messages this system publishes
- Cart Checked Out — a customer has checked out their cart.
Checkout System
v1.0.0InternalInternal system that orchestrates checkout. When a cart is checked out it reserves inventory, authorizes payment, and asks the Order Management System to create the order.
creates orders via
Uses the system. confirms checkout
Overview
The Checkout System drives the checkout flow at Acme Inc. When the Shopping domain checks out a cart, the Checkout API receives the Checkout Cart command and hands it to the Checkout Orchestrator. The orchestrator runs the checkout saga — reserving inventory via Reserve Inventory, authorizing payment via Authorize Payment, and finally creating the order via Create Order against the Order Management System.
Context Diagram
How this system relates to the other systems around it.
Resource Diagram
The services and messages that make up this system.
What's inside
| Component | Type | Responsibility |
|---|---|---|
| Checkout API | Service | Entry point for checkout. Receives the checkout command and starts the flow. |
| Checkout Orchestrator | Service | Runs the checkout saga — reserve inventory, authorize payment, create order. |
Messages this system sends
- Reserve Inventory — reserve stock for the items in the cart.
- Authorize Payment — authorize payment for the order total.
- Create Order — create the order in the Order Management System.
Architecture Graph
The checkout system's neighbourhood in the wider architecture.
Customer Management System
v1.0.0InternalInternal system that is the source of truth for customer profile data. Owns the customer database and publishes customer change events for the rest of the business to consume.
delegates authentication to
Uses the system. registers and updates their profile
Uses the system. looks up customer details
Overview
The Customer Management System is the system of record for customer profiles at Acme Inc. It accepts commands to register and update customers, persists them in the Customer Database, and emits domain events whenever customer data changes so downstream systems can react. It delegates authentication to the Identity Provider.
Context Diagram
How this system relates to the other systems around it.
Resource Diagram
The services, data stores and messages that make up this system.
What's inside
| Component | Type | Responsibility |
|---|---|---|
| Customer API | Service | Public-facing API. Handles register/update commands and customer reads, and publishes customer change events. |
| Customer Database | Data store | PostgreSQL system of record for all customer profile data. |
Messages this system publishes
When customer data changes, the system emits these events:
- Customer Registered — a new customer has registered.
- Customer Updated — an existing customer's profile has changed.
Finance Reporting System
v1.0.0Internal system that produces month-end finance reports. It works on its own, with no connections to other systems.
Overview
The Finance Reporting System produces month-end finance reports for the finance team. It is self-contained: it has no relationships with other systems and no actors, so its context diagram shows the system on its own.
Context Diagram
How this system relates to the other systems around it.
Resource Diagram
The services that make up this system.
What's inside
| Component | Type | Responsibility |
|---|---|---|
| Ledger Exporter | Service | Builds the month-end ledger export. |
Fraud Detection
Externalv1.0.0ExternalExternal provider that screens payments for fraud. It consumes payment requests and returns a pass or fail verdict.
screens payments for
Overview
Fraud Detection is an external provider Acme Inc uses to screen payments for fraud. It is owned and operated by a third party — modelled here as an external system so the catalog shows how the Payment Processing System integrates with it.
It consumes Payment Requested and returns a verdict via Fraud Check Passed or Fraud Check Failed.
Context Diagram
How this system relates to the other systems around it.
Resource Diagram
The services and messages that make up this system.
What's inside
| Component | Type | Responsibility |
|---|---|---|
| Fraud API | Service | Screens a payment for fraud and returns a pass/fail verdict. |
Messages this system publishes
- Fraud Check Passed — a payment passed fraud screening.
- Fraud Check Failed — a payment failed fraud screening.
Identity Provider
Externalv1.0.0IdentityThe identity system that authenticates customers. It is the source of truth for credentials and login, verifies sign-in attempts, and emits an event when a customer successfully authenticates.
provides authentication for
Uses the system. signs in
Overview
The Identity Provider authenticates customers for Acme Inc. It exposes an OAuth-style API, verifies credentials against the User Directory, and emits a Customer Authenticated event on a successful sign-in so other systems can react. It provides authentication for the Customer Management System.
Context Diagram
How this system relates to the other systems around it.
Resource Diagram
The services, data stores and messages that make up this system.
What's inside
| Component | Type | Responsibility |
|---|---|---|
| OAuth API | Service | OAuth-style authentication API. Handles authentication requests and publishes authentication events. |
| User Directory | Data store | The directory of customer credentials and identities. |
Messages this system publishes
- Customer Authenticated — a customer has successfully authenticated.
Inventory System
v1.0.0InternalInternal system that tracks stock and reserves it for orders. It is the source of truth for available inventory and confirms whether stock can be reserved.
provides stock for
Overview
The Inventory System owns stock levels at Acme Inc. During checkout it receives Reserve Inventory and confirms whether stock is available — replying with Inventory Reserved or Inventory Unavailable. It also handles Release Inventory (when a reservation is no longer needed) and serves Get Stock Level lookups from the Inventory Database.
Context Diagram
How this system relates to the other systems around it.
Resource Diagram
The services, data stores and messages that make up this system.
What's inside
| Component | Type | Responsibility |
|---|---|---|
| Inventory Service | Service | Reserves and releases stock, serves stock-level queries, and publishes inventory events. |
| Inventory Database | Data store | PostgreSQL system of record for stock levels and reservations. |
Messages this system publishes
- Inventory Reserved — stock was successfully reserved for an order.
- Inventory Unavailable — stock could not be reserved.
Loyalty System
v1.0.0InternalInternal system that calculates, stores and reverses customer loyalty points in response to order events.
Overview
The Loyalty System turns orders into rewards. The Loyalty Service consumes Order Completed and Order Cancelled from the Order Management System, updates balances in the Loyalty Database, and publishes points events for the rest of the business.
Resource Diagram
The services and messages that make up this system.
What's inside
| Component | Type | Responsibility |
|---|---|---|
| Loyalty Service | Service | Awards and reverses loyalty points and maintains balances. |
| Loyalty Database | Data store | Points ledger and customer balances. |
Messages this system sends
- Loyalty Points Earned — points were awarded for a completed order.
- Loyalty Points Reversed — points were removed after an order was cancelled.
Order Management System
v1.0.0InternalInternal system that is the source of truth for orders. It creates orders, tracks their lifecycle, and publishes events as orders are created, completed and cancelled.
receives orders from
Overview
The Order Management System owns the order at Acme Inc. It accepts the Create Order command from the Checkout System, persists orders in the Order Database, and serves order lookups via Get Order. As an order moves through its lifecycle it publishes Order Created, Order Completed and Order Cancelled events for the rest of the business to react to.
Context Diagram
How this system relates to the other systems around it.
Resource Diagram
The services, data stores and messages that make up this system.
What's inside
| Component | Type | Responsibility |
|---|---|---|
| Order Service | Service | Creates, cancels and serves orders, and publishes order lifecycle events. |
| Order Database | Data store | PostgreSQL system of record for orders and their items. |
Messages this system publishes
- Order Created — a new order has been created.
- Order Completed — an order has been fulfilled and completed.
- Order Cancelled — an order has been cancelled.
Payment Processing System
v1.0.0InternalInternal system that orchestrates payment for orders. It authorizes payments, requests charges from the external payment processor, handles the outcome, and issues refunds.
Overview
The Payment Processing System is the internal heart of the Payments domain. When the Ordering domain sends Authorize Payment, the Payment API records the intent in the Payment Database and the Payment Worker requests a charge from the external Stripe via Payment Requested. Stripe reports the outcome back as Payment Succeeded or Payment Failed, which the worker records. The system also issues refunds via Refund Requested.
Context Diagram
How this system relates to the other systems around it.
Resource Diagram
The services, data stores and messages that make up this system.
What's inside
| Component | Type | Responsibility |
|---|---|---|
| Payment API | Service | Receives authorization requests and records payment intent. |
| Payment Worker | Service | Drives charges and refunds against Stripe and records outcomes. |
| Payment Database | Data store | PostgreSQL system of record for payments and refunds. |
Messages this system publishes
- Payment Requested — a charge has been requested from the payment processor.
- Refund Requested — a refund has been requested from the payment processor.
Product Catalog System
v1.0.0InternalInternal system that is the source of truth for product data. Owns the product database and publishes product change events for the rest of the business to consume.
notifies of product changes
Uses the system. creates and updates products
Uses the system. manages categories and pricing
Overview
The Product Catalog System is the system of record for products at Acme Inc. It accepts commands to create, update and delete products, persists them in the Product Database, and emits domain events whenever product data changes so downstream systems — like the Search System — can react.
Context Diagram
How this system relates to the other systems around it.
Resource Diagram
The services, data stores and messages that make up this system.
What's inside
| Component | Type | Responsibility |
|---|---|---|
| Product API | Service | Public-facing API. Handles create/update/delete commands and product reads. |
| Product Worker | Service | Processes long-running and asynchronous catalog work off the request path. |
| Product Search Publisher | Service | Publishes product change events for the Search System to consume. |
| Product Database | Data store | PostgreSQL system of record for all product data. |
Messages this system publishes
When product data changes, the system emits these events:
- Product Created — a new product has been added to the catalog.
- Product Updated — an existing product's data has changed.
- Product Deleted — a product has been removed from the catalog.
adr-001-use-transactional-outbox— a product has been removed from the catalog.
Architecture decisions
The key decisions that shaped this system. Search, filter by status, or sort by clicking a column.
Promotion System
v1.0.0InternalInternal system that calculates the discounts and promotions that apply to a cart. It owns promotion rules and returns calculated discounts to the Cart System.
provides discounts to
Overview
The Promotion System owns the discount and promotion rules at Acme Inc. It receives requests to calculate the discount for a cart, evaluates the applicable rules from the Promotion Database, and publishes a Discount Calculated event with the result. It provides discounts to the Cart System.
Context Diagram
How this system relates to the other systems around it.
Resource Diagram
The services, data stores and messages that make up this system.
What's inside
| Component | Type | Responsibility |
|---|---|---|
| Promotion Service | Service | Evaluates promotion rules and calculates discounts for a cart. |
| Promotion Database | Data store | PostgreSQL store of promotion and discount rules. |
Messages this system publishes
- Discount Calculated — a discount has been calculated for a cart.
Returns System
v1.0.0InternalInternal system that accepts, approves and tracks customer returns through to their arrival back at the warehouse.
Overview
The Returns System owns the returns journey. The Returns API accepts Request Return from customers, and the Returns Processor approves returns and confirms receipt. Both share the Returns Database.
Resource Diagram
The services and messages that make up this system.
What's inside
| Component | Type | Responsibility |
|---|---|---|
| Returns API | Service | Accepts return requests from customers. |
| Returns Processor | Service | Applies the returns policy and tracks returned parcels. |
| Returns Database | Data store | Return requests and their status. |
Messages this system sends
- Return Requested — a customer asked to return items.
- Return Approved — the return passed policy checks.
- Return Received — returned items arrived at the warehouse.
Search System
v1.0.0InternalInternal system that keeps product data searchable. Consumes product change events from the Product Catalog System, maintains a search index, and serves fast product search to the rest of the business.
indexes product changes from
Uses the system. searches for products
Uses the system. integrates product search
Overview
The Search System makes the catalog discoverable. It subscribes to product change events published by the Product Catalog System, updates its Search Index, and exposes a search API so other teams can find products without ever touching the catalog database directly.
Context Diagram
How this system relates to the other systems around it.
Resource Diagram
The services, data stores and messages that make up this system.
What's inside
| Component | Type | Responsibility |
|---|---|---|
| Search API | Service | Public-facing API. Serves product search queries from the index. |
| Search Indexer | Service | Consumes product change events and keeps the search index up to date. |
| Search Index | Data store | The index that powers product search. |
Messages this system consumes
The Search System reacts to product changes published by the Product Catalog System:
- Product Created — index the new product.
- Product Updated — re-index the changed product.
- Product Deleted — remove the product from the index.
Shipping System
v1.0.0InternalInternal system that hands packed orders to carriers. It reacts to ready-for-shipping orders and creates shipments with an external carrier.
creates shipments with
Overview
The Shipping System connects Acme Inc to its carriers. When the Warehouse System publishes Order Ready For Shipping, the Shipping API selects a carrier and the Carrier Adapter sends a Create Shipment to the external Carrier to dispatch the parcel.
Context Diagram
How this system relates to the other systems around it.
Resource Diagram
The services and messages that make up this system.
What's inside
| Component | Type | Responsibility |
|---|---|---|
| Shipping API | Service | Receives ready-for-shipping orders and selects a carrier. |
| Carrier Adapter | Service | Translates and sends shipment requests to the external carrier. |
Messages this system sends
- Create Shipment — create a shipment with the carrier.
Stripe
Externalv1.0.0ExternalExternal payment processor used by Acme Inc to charge cards and issue refunds. It receives payment and refund requests and reports outcomes back via webhook events.
processes payments for
Overview
Stripe is the external payment processor Acme Inc uses to charge customer cards and issue refunds. It is owned and operated by Stripe — modelled here as an external system so the catalog shows how the Payment Processing System integrates with it.
Stripe receives Payment Requested and Refund Requested, and reports outcomes back via Payment Succeeded, Payment Failed and Refund Processed.
Context Diagram
How this system relates to the other systems around it.
Resource Diagram
The services and messages that make up this system.
What's inside
| Component | Type | Responsibility |
|---|---|---|
| Payments API | Service | Accepts charge and refund requests and processes them. |
| Webhook Endpoint | Service | Delivers payment and refund outcomes back to Acme Inc as webhook events. |
Messages this system publishes
- Payment Succeeded — a charge succeeded.
- Payment Failed — a charge failed.
- Refund Processed — a refund was processed.
Warehouse System
v1.0.0InternalInternal system that picks and packs orders in the warehouse. It reacts to completed orders, organises picking, and signals when an order is packed and ready to ship.
Overview
The Warehouse System turns a completed order into a packed parcel. When the Ordering domain publishes Order Completed, the Warehouse Service creates a picking job, the Picking Worker works through it, and the system publishes Order Packed and then Order Ready For Shipping for the Shipping System.
Context Diagram
How this system relates to the other systems around it.
Resource Diagram
The services, data stores and messages that make up this system.
What's inside
| Component | Type | Responsibility |
|---|---|---|
| Warehouse Service | Service | Receives completed orders and orchestrates picking and packing. |
| Picking Worker | Service | Works through picking jobs on the warehouse floor. |
| Warehouse Database | Data store | PostgreSQL store of picking jobs and their status. |
Messages this system publishes
- Order Packed — an order has been picked and packed.
- Order Ready For Shipping — a packed order is ready to be shipped.
Services
What runs, what it sends and what it listens to.
Carrier Adapter
v1.0.0Translates Acme Inc shipment requests into the external carrier's format and sends them to create a shipment.
Overview
The Carrier Adapter is the anti-corruption layer between Acme Inc and its carriers. It takes a shipment request from the Shipping API, maps it to the external Carrier's API, and sends a Create Shipment to dispatch the parcel.
Nothing in the catalog sends it messages.
Cart API
v1.0.0The public-facing API for shopping carts. Handles commands to add and remove items and to check out, and publishes an event when a cart is checked out.
Overview
The Cart API is the front door to the Cart System. It validates incoming commands, persists cart contents to the Cart Database, asks the Promotion System to calculate discounts via Calculate Discount, and publishes a Cart Checked Out event when the customer checks out.
Responsibilities
| Area | Description |
|---|---|
| Cart management | Validates and applies Add Item To Cart, Remove Item From Cart and Checkout Cart. |
| Discounts | Requests pricing from the Promotion System via Calculate Discount. |
| Event publishing | Emits Cart Checked Out when a cart is checked out. |
| Persistence | Reads from and writes to the Cart Database (system of record). |
Nothing in the catalog sends it messages.
Checkout API
v1.0.0The entry point to the Checkout System. Receives the checkout command from the Shopping domain and starts the checkout flow.
Overview
The Checkout API is the front door to the Checkout System. When the Shopping domain checks out a cart, this service receives the Checkout Cart command, validates it, and hands the work to the Checkout Orchestrator to run the checkout saga.
Responsibilities
| Area | Description |
|---|---|
| Checkout entry | Receives and validates Checkout Cart from the Shopping domain. |
| Orchestration handoff | Starts a checkout saga in the Checkout Orchestrator. |
Nothing in the catalog sends it messages.
Nothing in the catalog consumes its output.
Checkout Orchestrator
v1.0.0Runs the checkout saga. Reserves inventory, authorizes payment and creates the order, coordinating the steps that turn a checked-out cart into a confirmed order.
Overview
The Checkout Orchestrator is the brain of the Checkout System. Once the Checkout API hands it a checkout, it runs the checkout saga step by step:
- Reserve inventory — sends Reserve Inventory to hold stock for the cart's items.
- Authorize payment — sends Authorize Payment to authorize the order total.
- Create the order — sends Create Order to the Order Management System.
If any step fails, the orchestrator compensates the earlier steps (releasing the reservation, voiding the authorization) so the customer is never left in an inconsistent state.
Responsibilities
| Area | Description |
|---|---|
| Inventory | Reserves stock via Reserve Inventory. |
| Payment | Authorizes the order total via Authorize Payment. |
| Order creation | Creates the order via Create Order against the Order Management System. |
| Compensation | Rolls back earlier steps if a later step fails. |
Nothing in the catalog sends it messages.
Customer API
v1.0.0The public-facing API for customer profiles. Handles commands to register and update customers, serves customer reads, and publishes customer change events.
Overview
The Customer API is the front door to the Customer Management System. It validates incoming commands, persists customer data to the Customer Database, and publishes domain events (CustomerRegistered, CustomerUpdated) so the rest of the business can react to changes.
Responsibilities
| Area | Description |
|---|---|
| Command handling | Validates and applies Register Customer and Update Customer. |
| Reads | Serves Get Customer directly from the customer database. |
| Event publishing | Emits Customer Registered and Customer Updated on every change. |
| Persistence | Reads from and writes to the Customer Database (system of record). |
Nothing in the catalog sends it messages.
Nothing in the catalog consumes its output.
Fraud API
v1.0.0External fraud screening API. It consumes payment requests and returns a pass or fail verdict for each.
Overview
The Fraud API screens payments for fraud. It consumes Payment Requested from the Payment Processing System and returns a verdict — Fraud Check Passed or Fraud Check Failed — which the Payments domain uses to allow or block the charge.
Nothing in the catalog consumes its output.
Inventory Service
v1.0.0The system of record for stock. Reserves and releases inventory, serves stock-level queries, and publishes events when stock is reserved or unavailable.
Overview
The Inventory Service is the heart of the Inventory System. It receives Reserve Inventory during checkout and replies with Inventory Reserved or Inventory Unavailable. It also handles Release Inventory and serves Get Stock Level reads, all backed by the Inventory Database. When returned items arrive it consumes Return Received to restock them.
Responsibilities
| Area | Description |
|---|---|
| Reservations | Handles Reserve Inventory and Release Inventory. |
| Restocking | Consumes Return Received and returns resellable items to stock. |
| Lookups | Serves Get Stock Level from the Inventory Database. |
| Event publishing | Emits Inventory Reserved and Inventory Unavailable. |
Nothing in the catalog consumes its output.
Ledger Exporter
v1.0.0Builds the month-end ledger export used for finance reporting. It runs on a schedule and doesn't send or receive any messages.
Overview
The Ledger Exporter runs at the end of each month and builds the ledger export for the Finance Reporting System. It works on its own and doesn't send or receive any messages.
Nothing in the catalog sends it messages.
Nothing in the catalog consumes its output.
Loyalty Service
v1.0.0Awards loyalty points when orders complete and reverses them when orders are cancelled. Owns the points ledger and customer balances.
Overview
The Loyalty Service consumes Order Completed and Order Cancelled from the Ordering domain. It records points in the Loyalty Database and publishes Loyalty Points Earned or Loyalty Points Reversed so that promotions and customer notifications can react.
Responsibilities
| Area | Description |
|---|---|
| Earning | Awards points on Order Completed and emits Loyalty Points Earned. |
| Reversal | Removes points on Order Cancelled and emits Loyalty Points Reversed. |
| Persistence | Reads from and writes to the Loyalty Database. |
Notification Service
v1.0.0Sends customers email, SMS and push notifications in response to events from across Acme Inc, honouring each customer's channel preferences.
Overview
The Notification Service is the single place Acme Inc talks to customers outside the storefront. It consumes events from other domains, looks up the customer's channel choices in Notification Preferences, sends the message and publishes Customer Notified.
Notifications sent
| Event | Customer message |
|---|---|
| Order Confirmed | Order confirmation with summary and delivery estimate. |
| Shipment Delivered | Delivery confirmation. |
| Payment Failed | Ask the customer to update their payment method. |
| Refund Processed | Refund confirmation. |
| Review Published | Let the reviewer know their review is live. |
| Loyalty Points Earned | New points balance. |
| Return Approved | Return label and drop-off instructions. |
Nothing in the catalog consumes its output.
OAuth API
v1.0.0OAuth-style authentication API for the Identity Provider. Verifies customer credentials and publishes an event when a customer successfully authenticates.
Overview
The OAuth API is the authentication entry point for Acme Inc. It verifies credentials against the User Directory and, on a successful sign-in, publishes a Customer Authenticated event so other systems can react.
Responsibilities
| Area | Description |
|---|---|
| Authentication | Handles Authenticate Customer and verifies credentials. |
| Event publishing | Emits Customer Authenticated on a successful sign-in. |
| Credentials | Reads from the User Directory — the source of truth for credentials. |
Nothing in the catalog sends it messages.
Nothing in the catalog consumes its output.
Order Service
v1.0.0The system of record for orders. Creates and cancels orders, serves order lookups, and publishes events as orders move through their lifecycle.
Overview
The Order Service is the heart of the Order Management System. It receives Create Order from the Checkout System, persists orders to the Order Database, and serves order lookups via Get Order. It also handles Cancel Order, and consumes Order Packed from the Fulfilment domain to track when an order has been packed. As orders move through their lifecycle it publishes detailed events covering creation, confirmation, amendments, operational holds, fulfilment, completion, cancellation, and archival.
Responsibilities
| Area | Description |
|---|---|
| Order creation | Handles Create Order from the Checkout System and persists the order. |
| Order cancellation | Handles Cancel Order and compensates downstream where needed. |
| Order lookups | Serves Get Order from the Order Database. |
| Event publishing | Emits a complete order lifecycle stream for fulfilment, customer communications, support, and analytics consumers. |
Payment API
v1.0.0Receives payment authorization requests from the Ordering domain and records the payment intent, kicking off the charge against the payment processor.
Overview
The Payment API is the entry point to the Payment Processing System. It receives Authorize Payment from the Ordering domain, records the payment intent in the Payment Database, and leaves the Payment Worker to drive the charge against Stripe.
Responsibilities
| Area | Description |
|---|---|
| Authorization | Receives and validates Authorize Payment. |
| Persistence | Records payment intent in the Payment Database. |
Architecture Graph
How PaymentAPI connects to the rest of the catalog — the messages it exchanges and the systems around it.
Nothing in the catalog consumes its output.
Payment Worker
v1.0.0Drives charges and refunds against the external payment processor and records the outcomes. It requests payments and refunds, and consumes the success/failure events Stripe returns.
Overview
The Payment Worker drives money movement. It requests charges from the external Stripe via Payment Requested and refunds via Refund Requested, then consumes the Payment Succeeded and Payment Failed events Stripe returns and records the outcome in the Payment Database. It also refunds customers for returned items when the Fulfilment domain publishes Return Received.
Responsibilities
| Area | Description |
|---|---|
| Charging | Requests charges via Payment Requested. |
| Refunds | Requests refunds via Refund Requested. |
| Returns | Consumes Return Received and requests a refund for the returned items. |
| Outcomes | Consumes Payment Succeeded / Payment Failed and records them. |
| Persistence | Reads from and writes to the Payment Database. |
Payments API
v1.0.0Stripe's API for charging cards and issuing refunds. Acme Inc's Payment Processing System calls it to request payments and refunds.
Overview
The Payments API is Stripe's external interface for charging cards and issuing refunds. The Payment Processing System sends Payment Requested and Refund Requested, and Stripe processes them and reports the outcome back through its Webhook Endpoint.
Nothing in the catalog consumes its output.
Picking Worker
v1.0.0Works through picking jobs on the warehouse floor and signals when an order has been picked and packed.
Overview
The Picking Worker processes picking jobs created by the Warehouse Service. As warehouse staff pick and pack each order, the worker updates the job in the Warehouse Database and publishes Order Packed when the order is complete.
Nothing in the catalog sends it messages.
Product API
v1.0.0The public-facing API for the product catalog. Handles commands to create, update and delete products, serves product reads, and is the entry point into the Product Catalog System.
Overview
The Product API is the front door to the Product Catalog System. It validates incoming commands, persists product data to the Product Database, and records every change to the outbox. The Product Search Publisher then turns those changes into the domain events the rest of the business consumes.
Responsibilities
| Area | Description |
|---|---|
| Command handling | Validates and applies Create Product, Update Product and Delete Product. |
| Reads | Serves Get Product directly from the product database. |
| Change capture | Records every product change to the outbox in the Product Database for the Product Search Publisher to publish. |
| Persistence | Reads from and writes to the Product Database (system of record). |
Nothing in the catalog sends it messages.
Nothing in the catalog consumes its output.
Product Search Publisher
v1.0.0Reads product changes from the product database (outbox) and reliably publishes product-created, product-updated and product-deleted events for the Search System to consume.
Overview
The Product Search Publisher is the bridge between the Product Catalog System and the rest of the business. It uses the transactional outbox pattern: the Product API records every product change in the Product Database, and this service reliably reads those changes and publishes them as Product Created, Product Updated and Product Deleted events.
This guarantees that product changes are never lost and are delivered to the Search System in order.
Responsibilities
| Area | Description |
|---|---|
| Outbox polling | Reads unpublished product changes from the Product Database. |
| Reliable publishing | Publishes Product Created, Product Updated and Product Deleted with at-least-once delivery. |
| Ordering | Preserves per-product ordering of change events. |
Nothing in the catalog sends it messages.
Product Worker
v1.0.0Background worker that handles long-running and asynchronous catalog work off the request path, such as enrichment, image processing and bulk imports.
Overview
The Product Worker keeps the Product API fast by taking slow or asynchronous work off the request path. It reads from and writes back to the Product Database, handling jobs like data enrichment, image processing and bulk catalog imports.
Responsibilities
| Area | Description |
|---|---|
| Enrichment | Augments product records with derived data after they are created or updated. |
| Media | Processes and optimises product images asynchronously. |
| Bulk imports | Ingests large product feeds without blocking the API. |
| Persistence | Reads from and writes to the Product Database. |
Nothing in the catalog sends it messages.
Nothing in the catalog consumes its output.
Promotion Service
v1.0.0Evaluates promotion rules and calculates the discount that applies to a cart. Receives discount requests and publishes the calculated result.
Overview
The Promotion Service is the heart of the Promotion System. It receives Calculate Discount requests from the Cart System, evaluates the applicable rules from the Promotion Database, and publishes a Discount Calculated event with the result. It also consumes Loyalty Points Earned from the Customer domain to unlock loyalty-tier promotions.
Responsibilities
| Area | Description |
|---|---|
| Discount calculation | Handles Calculate Discount and evaluates promotion rules. |
| Loyalty promotions | Consumes Loyalty Points Earned to unlock loyalty-tier promotions for the customer. |
| Rules | Reads promotion and discount rules from the Promotion Database. |
| Event publishing | Emits Discount Calculated with the calculated result. |
Nothing in the catalog consumes its output.
Rating Aggregator
v1.0.0Keeps each product's aggregate star rating up to date as reviews are published, and serves it fast from a cache.
Overview
The Rating Aggregator consumes Review Published and recomputes the affected product's aggregate rating (average score and review count). It writes the result to the Rating Cache for fast reads and publishes Rating Updated so other domains can stay in sync.
Responsibilities
| Area | Description |
|---|---|
| Aggregation | Recomputes average rating and review count per product. |
| Caching | Writes aggregate ratings to the Rating Cache. |
| Eventing | Publishes Rating Updated on every change. |
Nothing in the catalog consumes its output.
Returns API
v1.0.0Public API customers use to start a return. Validates the request against the original order and records it.
Overview
The Returns API receives Request Return from customers, stores the request in the Returns Database and publishes Return Requested for the Returns Processor.
Responsibilities
| Area | Description |
|---|---|
| Intake | Handles Request Return and validates the order and items. |
| Persistence | Writes new return requests to the Returns Database. |
| Event publishing | Emits Return Requested. |
Nothing in the catalog sends it messages.
Returns Processor
v1.0.0Applies the returns policy to new requests and tracks returned parcels until they arrive back at the warehouse.
Overview
The Returns Processor consumes Return Requested, checks the returns window and item eligibility, and publishes Return Approved. When the warehouse scans the returned parcel it publishes Return Received, which Payments uses to refund the customer and Inventory uses to restock.
Responsibilities
| Area | Description |
|---|---|
| Approval | Applies the returns policy and emits Return Approved. |
| Receipt | Confirms returned items arrived and emits Return Received. |
| Persistence | Reads from and writes to the Returns Database. |
Review API
v1.0.0The public-facing API for product reviews. Accepts review submissions, serves published reviews, and is the entry point into the Reviews & Ratings domain.
Overview
The Review API is the front door to the Reviews & Ratings domain. It validates incoming Submit Review commands, persists reviews to the Review Database, and publishes Review Submitted. It also serves Get Product Reviews, reading published reviews from the Review Database and aggregate ratings from the Rating Cache.
Responsibilities
| Area | Description |
|---|---|
| Command handling | Validates and applies Submit Review. |
| Reads | Serves Get Product Reviews from the review database and rating cache. |
| Eventing | Publishes Review Submitted for moderation. |
| Persistence | Writes to the Review Database; reads from the Review Database and Rating Cache. |
Nothing in the catalog sends it messages.
Review Moderation Worker
v1.0.0Asynchronous worker that screens submitted reviews for spam, abuse and policy violations, then publishes or rejects them.
Overview
The Review Moderation Worker consumes Review Submitted (and Review Flagged for already-published reviews), screens each review (automated checks plus thresholds for manual review), and records the outcome on the Review Database. It then publishes either Review Published or Review Rejected.
Responsibilities
| Area | Description |
|---|---|
| Moderation | Screens reviews for spam, abuse and policy violations. |
| Outcome | Publishes Review Published or Review Rejected. |
| Persistence | Records the moderation decision on the Review Database. |
Search API
v1.0.0Public-facing API that serves fast, relevant product search to the rest of the business, reading from the search index.
Overview
The Search API is the front door to the Search System. It answers Search Products queries by reading from the Search Index, which is kept current by the Search Indexer. Other teams use this API so they never have to query the catalog database directly.
Responsibilities
| Area | Description |
|---|---|
| Search | Serves Search Products with full-text matching, filtering and pagination. |
| Reads | Queries the Search Index — never the catalog database. |
Nothing in the catalog sends it messages.
Nothing in the catalog consumes its output.
Search Indexer
v1.0.0Consumes product change events from the Product Catalog System and keeps the search index up to date so products are discoverable.
Overview
The Search Indexer is how the Search System stays in sync with the catalog. It subscribes to Product Created, Product Updated and Product Deleted events published by the Product Catalog System and applies each change to the Search Index.
Responsibilities
| Event | Action |
|---|---|
| Product Created | Add the new product to the Search Index. |
| Product Updated | Re-index the changed product. |
| Product Deleted | Remove the product from the index. |
Nothing in the catalog consumes its output.
Shipping API
v1.0.0Receives ready-for-shipping orders, selects a carrier, and kicks off shipment creation.
Overview
The Shipping API is the entry point to the Shipping System. It consumes Order Ready For Shipping from the Warehouse System, selects an appropriate carrier, and hands off to the Carrier Adapter to create the shipment.
Nothing in the catalog consumes its output.
Shipping API
v1.0.0The carrier's API for creating shipments. Acme Inc's Shipping System calls it to dispatch packed orders.
Overview
The Shipping API is the carrier's external interface for creating shipments. The Shipping System sends Create Shipment, and the carrier dispatches the parcel and begins reporting progress through its Tracking API.
Nothing in the catalog consumes its output.
Tracking API
v1.0.0The carrier's API for reporting delivery progress. It notifies Acme Inc when a shipment is created, delivered, or fails.
Overview
The Tracking API is how the carrier reports delivery progress back to Acme Inc. After a shipment is created via the Shipping API, it emits Shipment Created, then Shipment Delivered on success or Shipment Failed if delivery cannot be completed.
Nothing in the catalog sends it messages.
Warehouse Service
v1.0.0Orchestrates picking and packing in the warehouse. It reacts to completed orders, creates picking jobs, and signals when an order is ready to ship.
Overview
The Warehouse Service runs warehousing. When the Ordering domain publishes Order Completed, it creates a picking job in the Warehouse Database for the Picking Worker to work through. Once the order is packed it publishes Order Ready For Shipping for the Shipping System.
Webhook Endpoint
v1.0.0Stripe's webhook delivery for payment and refund outcomes. It notifies Acme Inc whether a charge succeeded or failed, and when a refund is processed.
Overview
The Webhook Endpoint is how Stripe reports outcomes back to Acme Inc. After processing a request from the Payments API, it delivers Payment Succeeded, Payment Failed or Refund Processed to the Payment Processing System.
Nothing in the catalog sends it messages.
Events
Facts that happened. Published once, read by any number of consumers.
Cart Checked Out
EVTv1.0.0Broker:KafkaPublished when a customer has checked out their cart.
Emitted when a customer checks out their cart
eventIdstring uuidRequiredoccurredAtstring date-timeRequiredcartIdstring uuidRequiredcustomerIdstring uuidRequireditemsarray of objectRequiredproductIdstring uuidRequiredquantityintegerRequired1unitPriceintegerRequiredPrice per unit in minor units (e.g. cents)
subtotalintegerTotal before discounts, in minor units (e.g. cents)
discountintegerTotal discount applied, in minor units (e.g. cents)
totalintegerRequiredFinal total, in minor units (e.g. cents)
currencystringRequired^[A-Z]{3}$Overview
CartCheckedOut is published by the Cart API when a customer checks out. Downstream systems consume this event to create an order, take payment, and begin fulfilment.
Nothing in the catalog.
{
"eventId": "3f6b2b8e-9a4c-4f0e-8f2a-1c2d3e4f5a6b",
"occurredAt": "2026-01-01T12:00:00Z",
"cartId": "3f6b2b8e-9a4c-4f0e-8f2a-1c2d3e4f5a6b",
"customerId": "3f6b2b8e-9a4c-4f0e-8f2a-1c2d3e4f5a6b",
"items": [
{
"productId": "3f6b2b8e-9a4c-4f0e-8f2a-1c2d3e4f5a6b",
"quantity": 1,
"unitPrice": 0
}
],
"subtotal": 0,
"discount": 0,
"total": 0,
"currency": "string"
}/** Emitted when a customer checks out their cart */
export interface CartCheckedOut {
eventId: string;
occurredAt: string;
cartId: string;
customerId: string;
items: {
productId: string;
quantity: number;
/** Price per unit in minor units (e.g. cents) */
unitPrice: number;
}[];
/** Total before discounts, in minor units (e.g. cents) */
subtotal?: number;
/** Total discount applied, in minor units (e.g. cents) */
discount?: number;
/** Final total, in minor units (e.g. cents) */
total: number;
currency: string;
}{
"$schema": "http://json-schema.org/draft-07/schema#",
"title": "CartCheckedOut",
"description": "Emitted when a customer checks out their cart",
"type": "object",
"properties": {
"eventId": {
"type": "string",
"format": "uuid"
},
"occurredAt": {
"type": "string",
"format": "date-time"
},
"cartId": {
"type": "string",
"format": "uuid"
},
"customerId": {
"type": "string",
"format": "uuid"
},
"items": {
"type": "array",
"items": {
"type": "object",
"properties": {
"productId": {
"type": "string",
"format": "uuid"
},
"quantity": {
"type": "integer",
"minimum": 1
},
"unitPrice": {
"description": "Price per unit in minor units (e.g. cents)",
"type": "integer"
}
},
"required": [
"productId",
"quantity",
"unitPrice"
]
}
},
"subtotal": {
"description": "Total before discounts, in minor units (e.g. cents)",
"type": "integer"
},
"discount": {
"description": "Total discount applied, in minor units (e.g. cents)",
"type": "integer"
},
"total": {
"description": "Final total, in minor units (e.g. cents)",
"type": "integer"
},
"currency": {
"type": "string",
"pattern": "^[A-Z]{3}$"
}
},
"required": [
"eventId",
"occurredAt",
"cartId",
"customerId",
"items",
"total",
"currency"
]
}Customer Authenticated
EVTv1.0.0Broker:KafkaPublished when a customer has successfully authenticated.
Emitted when a customer successfully authenticates
eventIdstring uuidRequiredUnique identifier for this event
occurredAtstring date-timeRequiredTime the customer authenticated
customerIdstring uuidRequiredUnique identifier of the customer that authenticated
methodstringRequiredHow the customer authenticated
PASSWORDSSOMFAipAddressstringIP address the sign-in came from
Overview
CustomerAuthenticated is published by the OAuth API whenever a customer successfully signs in. Other systems consume this event for auditing, session tracking, and security monitoring.
Nothing in the catalog.
{
"eventId": "3f6b2b8e-9a4c-4f0e-8f2a-1c2d3e4f5a6b",
"occurredAt": "2026-01-01T12:00:00Z",
"customerId": "3f6b2b8e-9a4c-4f0e-8f2a-1c2d3e4f5a6b",
"method": "PASSWORD",
"ipAddress": "string"
}/** Emitted when a customer successfully authenticates */
export interface CustomerAuthenticated {
/** Unique identifier for this event */
eventId: string;
/** Time the customer authenticated */
occurredAt: string;
/** Unique identifier of the customer that authenticated */
customerId: string;
/** How the customer authenticated */
method: "PASSWORD" | "SSO" | "MFA";
/** IP address the sign-in came from */
ipAddress?: string;
}{
"$schema": "http://json-schema.org/draft-07/schema#",
"title": "CustomerAuthenticated",
"description": "Emitted when a customer successfully authenticates",
"type": "object",
"properties": {
"eventId": {
"description": "Unique identifier for this event",
"type": "string",
"format": "uuid"
},
"occurredAt": {
"description": "Time the customer authenticated",
"type": "string",
"format": "date-time"
},
"customerId": {
"description": "Unique identifier of the customer that authenticated",
"type": "string",
"format": "uuid"
},
"method": {
"description": "How the customer authenticated",
"type": "string",
"enum": [
"PASSWORD",
"SSO",
"MFA"
]
},
"ipAddress": {
"description": "IP address the sign-in came from",
"type": "string"
}
},
"required": [
"eventId",
"occurredAt",
"customerId",
"method"
]
}Customer Notified
EVTv1.0.0Broker:KafkaPublished after a notification has been sent to a customer on one of their preferred channels.
Published after a notification has been sent to a customer
notificationIdstring uuidRequiredcustomerIdstring uuidRequiredchannelstringRequiredemailsmspushtemplatestringRequiredTemplate key, e.g. order-confirmed
sourceEventstringName of the event that triggered the notification
sentAtstring date-timeRequiredOverview
CustomerNotified is published by the Notification Service each time it delivers a notification. It gives support and analytics an audit trail of what each customer was told, when, and on which channel.
Nothing in the catalog.
{
"notificationId": "3f6b2b8e-9a4c-4f0e-8f2a-1c2d3e4f5a6b",
"customerId": "3f6b2b8e-9a4c-4f0e-8f2a-1c2d3e4f5a6b",
"channel": "email",
"template": "string",
"sourceEvent": "string",
"sentAt": "2026-01-01T12:00:00Z"
}/** Published after a notification has been sent to a customer */
export interface CustomerNotified {
notificationId: string;
customerId: string;
channel: "email" | "sms" | "push";
/** Template key, e.g. order-confirmed */
template: string;
/** Name of the event that triggered the notification */
sourceEvent?: string;
sentAt: string;
}{
"$schema": "http://json-schema.org/draft-07/schema#",
"title": "CustomerNotified",
"description": "Published after a notification has been sent to a customer",
"type": "object",
"properties": {
"notificationId": {
"type": "string",
"format": "uuid"
},
"customerId": {
"type": "string",
"format": "uuid"
},
"channel": {
"type": "string",
"enum": [
"email",
"sms",
"push"
]
},
"template": {
"type": "string",
"description": "Template key, e.g. order-confirmed"
},
"sourceEvent": {
"type": "string",
"description": "Name of the event that triggered the notification"
},
"sentAt": {
"type": "string",
"format": "date-time"
}
},
"required": [
"notificationId",
"customerId",
"channel",
"template",
"sentAt"
]
}Customer Registered
EVTv1.0.0Broker:KafkaPublished when a new customer has registered.
Emitted when a new customer registers
eventIdstring uuidRequiredUnique identifier for this event
occurredAtstring date-timeRequiredTime the customer registered
customerobjectRequiredThe customer that registered
customerIdstring uuidRequiredUnique identifier for the customer
emailstring emailRequiredCustomer's email address
namestringCustomer's full name
statusstringRequiredLifecycle status of the customer account
ACTIVESUSPENDEDCLOSEDOverview
CustomerRegistered is published by the Customer API whenever a new customer successfully registers. Downstream systems consume this event to onboard the customer.
Nothing in the catalog.
{
"eventId": "3f6b2b8e-9a4c-4f0e-8f2a-1c2d3e4f5a6b",
"occurredAt": "2026-01-01T12:00:00Z",
"customer": {
"customerId": "3f6b2b8e-9a4c-4f0e-8f2a-1c2d3e4f5a6b",
"email": "jane@example.com",
"name": "string",
"status": "ACTIVE"
}
}/** Emitted when a new customer registers */
export interface CustomerRegistered {
/** Unique identifier for this event */
eventId: string;
/** Time the customer registered */
occurredAt: string;
/** The customer that registered */
customer: {
/** Unique identifier for the customer */
customerId: string;
/** Customer's email address */
email: string;
/** Customer's full name */
name?: string;
/** Lifecycle status of the customer account */
status: "ACTIVE" | "SUSPENDED" | "CLOSED";
};
}{
"$schema": "http://json-schema.org/draft-07/schema#",
"title": "CustomerRegistered",
"description": "Emitted when a new customer registers",
"type": "object",
"properties": {
"eventId": {
"description": "Unique identifier for this event",
"type": "string",
"format": "uuid"
},
"occurredAt": {
"description": "Time the customer registered",
"type": "string",
"format": "date-time"
},
"customer": {
"description": "The customer that registered",
"type": "object",
"properties": {
"customerId": {
"description": "Unique identifier for the customer",
"type": "string",
"format": "uuid"
},
"email": {
"description": "Customer's email address",
"type": "string",
"format": "email"
},
"name": {
"description": "Customer's full name",
"type": "string"
},
"status": {
"description": "Lifecycle status of the customer account",
"type": "string",
"enum": [
"ACTIVE",
"SUSPENDED",
"CLOSED"
]
}
},
"required": [
"customerId",
"email",
"status"
]
}
},
"required": [
"eventId",
"occurredAt",
"customer"
]
}Customer Updated
EVTv1.0.0Broker:KafkaPublished when an existing customer's profile has changed.
Emitted when an existing customer's profile changes
eventIdstring uuidRequiredUnique identifier for this event
occurredAtstring date-timeRequiredTime the customer was updated
customerIdstring uuidRequiredUnique identifier for the customer that changed
changesobjectRequiredThe fields that changed and their new values
emailstring emailnamestringstatusstringACTIVESUSPENDEDCLOSEDOverview
CustomerUpdated is published by the Customer API whenever an existing customer's profile changes. Downstream systems consume this event to keep their copy of customer data in sync.
Nothing in the catalog.
{
"eventId": "3f6b2b8e-9a4c-4f0e-8f2a-1c2d3e4f5a6b",
"occurredAt": "2026-01-01T12:00:00Z",
"customerId": "3f6b2b8e-9a4c-4f0e-8f2a-1c2d3e4f5a6b",
"changes": {
"email": "jane@example.com",
"name": "string",
"status": "ACTIVE"
}
}/** Emitted when an existing customer's profile changes */
export interface CustomerUpdated {
/** Unique identifier for this event */
eventId: string;
/** Time the customer was updated */
occurredAt: string;
/** Unique identifier for the customer that changed */
customerId: string;
/** The fields that changed and their new values */
changes: {
email?: string;
name?: string;
status?: "ACTIVE" | "SUSPENDED" | "CLOSED";
};
}{
"$schema": "http://json-schema.org/draft-07/schema#",
"title": "CustomerUpdated",
"description": "Emitted when an existing customer's profile changes",
"type": "object",
"properties": {
"eventId": {
"description": "Unique identifier for this event",
"type": "string",
"format": "uuid"
},
"occurredAt": {
"description": "Time the customer was updated",
"type": "string",
"format": "date-time"
},
"customerId": {
"description": "Unique identifier for the customer that changed",
"type": "string",
"format": "uuid"
},
"changes": {
"description": "The fields that changed and their new values",
"type": "object",
"properties": {
"email": {
"type": "string",
"format": "email"
},
"name": {
"type": "string"
},
"status": {
"type": "string",
"enum": [
"ACTIVE",
"SUSPENDED",
"CLOSED"
]
}
},
"minProperties": 1
}
},
"required": [
"eventId",
"occurredAt",
"customerId",
"changes"
]
}Discount Calculated
EVTv1.0.0Broker:KafkaPublished when a discount has been calculated for a cart.
Emitted when a discount has been calculated for a cart
eventIdstring uuidRequiredoccurredAtstring date-timeRequiredcartIdstring uuidRequireddiscountintegerRequiredTotal discount applied, in minor units (e.g. cents)
0currencystringRequired^[A-Z]{3}$appliedPromotionsarray of stringIdentifiers of the promotions that were applied
Overview
DiscountCalculated is published by the Promotion Service after evaluating the promotion rules for a cart. The Cart System uses the result to price the cart, and other systems can consume it for analytics.
Nothing in the catalog.
{
"eventId": "3f6b2b8e-9a4c-4f0e-8f2a-1c2d3e4f5a6b",
"occurredAt": "2026-01-01T12:00:00Z",
"cartId": "3f6b2b8e-9a4c-4f0e-8f2a-1c2d3e4f5a6b",
"discount": 0,
"currency": "string",
"appliedPromotions": [
"string"
]
}/** Emitted when a discount has been calculated for a cart */
export interface DiscountCalculated {
eventId: string;
occurredAt: string;
cartId: string;
/** Total discount applied, in minor units (e.g. cents) */
discount: number;
currency: string;
/** Identifiers of the promotions that were applied */
appliedPromotions?: string[];
}{
"$schema": "http://json-schema.org/draft-07/schema#",
"title": "DiscountCalculated",
"description": "Emitted when a discount has been calculated for a cart",
"type": "object",
"properties": {
"eventId": {
"type": "string",
"format": "uuid"
},
"occurredAt": {
"type": "string",
"format": "date-time"
},
"cartId": {
"type": "string",
"format": "uuid"
},
"discount": {
"description": "Total discount applied, in minor units (e.g. cents)",
"type": "integer",
"minimum": 0
},
"currency": {
"type": "string",
"pattern": "^[A-Z]{3}$"
},
"appliedPromotions": {
"description": "Identifiers of the promotions that were applied",
"type": "array",
"items": {
"type": "string"
}
}
},
"required": [
"eventId",
"occurredAt",
"cartId",
"discount",
"currency"
]
}Fraud Check Failed
EVTv1.0.0Broker:KafkaPublished when a payment fails fraud screening.
Published when a payment fails fraud screening
paymentIdstring uuidRequiredorderIdstring uuidRequiredscorenumberFraud risk score; higher is riskier
0Maximum 1reasonstringRequiredHIGH_RISK_SCOREBLOCKLISTEDVELOCITYMISMATCHcheckedAtstring date-timeRequiredOverview
FraudCheckFailed is published by the Fraud API when a payment is flagged as fraudulent. The Payment Processing System uses it to block the charge and cancel the order.
Nothing in the catalog.
{
"paymentId": "3f6b2b8e-9a4c-4f0e-8f2a-1c2d3e4f5a6b",
"orderId": "3f6b2b8e-9a4c-4f0e-8f2a-1c2d3e4f5a6b",
"score": 0,
"reason": "HIGH_RISK_SCORE",
"checkedAt": "2026-01-01T12:00:00Z"
}/** Published when a payment fails fraud screening */
export interface FraudCheckFailed {
paymentId: string;
orderId: string;
/** Fraud risk score; higher is riskier */
score?: number;
reason: "HIGH_RISK_SCORE" | "BLOCKLISTED" | "VELOCITY" | "MISMATCH";
checkedAt: string;
}{
"$schema": "http://json-schema.org/draft-07/schema#",
"title": "FraudCheckFailed",
"description": "Published when a payment fails fraud screening",
"type": "object",
"properties": {
"paymentId": {
"type": "string",
"format": "uuid"
},
"orderId": {
"type": "string",
"format": "uuid"
},
"score": {
"type": "number",
"minimum": 0,
"maximum": 1,
"description": "Fraud risk score; higher is riskier"
},
"reason": {
"type": "string",
"enum": [
"HIGH_RISK_SCORE",
"BLOCKLISTED",
"VELOCITY",
"MISMATCH"
]
},
"checkedAt": {
"type": "string",
"format": "date-time"
}
},
"required": [
"paymentId",
"orderId",
"reason",
"checkedAt"
]
}Fraud Check Passed
EVTv1.0.0Broker:KafkaPublished when a payment passes fraud screening.
Published when a payment passes fraud screening
paymentIdstring uuidRequiredorderIdstring uuidRequiredscorenumberFraud risk score; lower is safer
0Maximum 1checkedAtstring date-timeRequiredOverview
FraudCheckPassed is published by the Fraud API when a payment clears fraud screening. The Payment Processing System uses it to allow the charge to proceed.
Nothing in the catalog.
{
"paymentId": "3f6b2b8e-9a4c-4f0e-8f2a-1c2d3e4f5a6b",
"orderId": "3f6b2b8e-9a4c-4f0e-8f2a-1c2d3e4f5a6b",
"score": 0,
"checkedAt": "2026-01-01T12:00:00Z"
}/** Published when a payment passes fraud screening */
export interface FraudCheckPassed {
paymentId: string;
orderId: string;
/** Fraud risk score; lower is safer */
score?: number;
checkedAt: string;
}{
"$schema": "http://json-schema.org/draft-07/schema#",
"title": "FraudCheckPassed",
"description": "Published when a payment passes fraud screening",
"type": "object",
"properties": {
"paymentId": {
"type": "string",
"format": "uuid"
},
"orderId": {
"type": "string",
"format": "uuid"
},
"score": {
"type": "number",
"minimum": 0,
"maximum": 1,
"description": "Fraud risk score; lower is safer"
},
"checkedAt": {
"type": "string",
"format": "date-time"
}
},
"required": [
"paymentId",
"orderId",
"checkedAt"
]
}Inventory Reserved
EVTv1.0.0Broker:KafkaPublished when stock has been successfully reserved for an order.
Published when stock has been successfully reserved for an order
reservationIdstring uuidRequiredorderIdstring uuidcartIdstring uuiditemsarray of objectRequiredproductIdstring uuidRequiredquantityintegerRequired1reservedAtstring date-timeRequiredOverview
InventoryReserved is published by the Inventory Service when stock for an order has been successfully reserved. The Ordering domain's checkout saga relies on this to continue placing the order.
Nothing in the catalog.
{
"reservationId": "3f6b2b8e-9a4c-4f0e-8f2a-1c2d3e4f5a6b",
"orderId": "3f6b2b8e-9a4c-4f0e-8f2a-1c2d3e4f5a6b",
"cartId": "3f6b2b8e-9a4c-4f0e-8f2a-1c2d3e4f5a6b",
"items": [
{
"productId": "3f6b2b8e-9a4c-4f0e-8f2a-1c2d3e4f5a6b",
"quantity": 1
}
],
"reservedAt": "2026-01-01T12:00:00Z"
}/** Published when stock has been successfully reserved for an order */
export interface InventoryReserved {
reservationId: string;
orderId?: string;
cartId?: string;
items: {
productId: string;
quantity: number;
}[];
reservedAt: string;
}{
"$schema": "http://json-schema.org/draft-07/schema#",
"title": "InventoryReserved",
"description": "Published when stock has been successfully reserved for an order",
"type": "object",
"properties": {
"reservationId": {
"type": "string",
"format": "uuid"
},
"orderId": {
"type": "string",
"format": "uuid"
},
"cartId": {
"type": "string",
"format": "uuid"
},
"items": {
"type": "array",
"items": {
"type": "object",
"properties": {
"productId": {
"type": "string",
"format": "uuid"
},
"quantity": {
"type": "integer",
"minimum": 1
}
},
"required": [
"productId",
"quantity"
]
}
},
"reservedAt": {
"type": "string",
"format": "date-time"
}
},
"required": [
"reservationId",
"items",
"reservedAt"
]
}Loyalty Points Earned
EVTv1.0.0Broker:KafkaPublished when a customer earns loyalty points for a completed order.
Published when a customer earns loyalty points for a completed order
customerIdstring uuidRequiredorderIdstring uuidRequiredpointsEarnedintegerRequired1newBalanceintegerRequired0tierstringbronzesilvergoldearnedAtstring date-timeRequiredOverview
LoyaltyPointsEarned is published by the Loyalty Service after it awards points for an Order Completed. The Shopping domain uses it to unlock loyalty promotions, and Customer Notifications tells the customer about their new balance.
{
"customerId": "3f6b2b8e-9a4c-4f0e-8f2a-1c2d3e4f5a6b",
"orderId": "3f6b2b8e-9a4c-4f0e-8f2a-1c2d3e4f5a6b",
"pointsEarned": 1,
"newBalance": 0,
"tier": "bronze",
"earnedAt": "2026-01-01T12:00:00Z"
}/** Published when a customer earns loyalty points for a completed order */
export interface LoyaltyPointsEarned {
customerId: string;
orderId: string;
pointsEarned: number;
newBalance: number;
tier?: "bronze" | "silver" | "gold";
earnedAt: string;
}{
"$schema": "http://json-schema.org/draft-07/schema#",
"title": "LoyaltyPointsEarned",
"description": "Published when a customer earns loyalty points for a completed order",
"type": "object",
"properties": {
"customerId": {
"type": "string",
"format": "uuid"
},
"orderId": {
"type": "string",
"format": "uuid"
},
"pointsEarned": {
"type": "integer",
"minimum": 1
},
"newBalance": {
"type": "integer",
"minimum": 0
},
"tier": {
"type": "string",
"enum": [
"bronze",
"silver",
"gold"
]
},
"earnedAt": {
"type": "string",
"format": "date-time"
}
},
"required": [
"customerId",
"orderId",
"pointsEarned",
"newBalance",
"earnedAt"
]
}Loyalty Points Reversed
EVTv1.0.0Broker:KafkaPublished when loyalty points are removed from a customer because the order that earned them was cancelled.
Published when loyalty points are reversed for a cancelled order
customerIdstring uuidRequiredorderIdstring uuidRequiredpointsReversedintegerRequired1newBalanceintegerRequired0reasonstringorder_cancelledorder_refundedreversedAtstring date-timeRequiredOverview
LoyaltyPointsReversed is published by the Loyalty Service when it handles an Order Cancelled for an order that had already earned points. It keeps downstream balances and promotions consistent with the points ledger.
Nothing in the catalog.
{
"customerId": "3f6b2b8e-9a4c-4f0e-8f2a-1c2d3e4f5a6b",
"orderId": "3f6b2b8e-9a4c-4f0e-8f2a-1c2d3e4f5a6b",
"pointsReversed": 1,
"newBalance": 0,
"reason": "order_cancelled",
"reversedAt": "2026-01-01T12:00:00Z"
}/** Published when loyalty points are reversed for a cancelled order */
export interface LoyaltyPointsReversed {
customerId: string;
orderId: string;
pointsReversed: number;
newBalance: number;
reason?: "order_cancelled" | "order_refunded";
reversedAt: string;
}{
"$schema": "http://json-schema.org/draft-07/schema#",
"title": "LoyaltyPointsReversed",
"description": "Published when loyalty points are reversed for a cancelled order",
"type": "object",
"properties": {
"customerId": {
"type": "string",
"format": "uuid"
},
"orderId": {
"type": "string",
"format": "uuid"
},
"pointsReversed": {
"type": "integer",
"minimum": 1
},
"newBalance": {
"type": "integer",
"minimum": 0
},
"reason": {
"type": "string",
"enum": [
"order_cancelled",
"order_refunded"
]
},
"reversedAt": {
"type": "string",
"format": "date-time"
}
},
"required": [
"customerId",
"orderId",
"pointsReversed",
"newBalance",
"reversedAt"
]
}Order Amended
EVTv1.0.0Broker:KafkaPublished when an accepted order is changed before fulfilment begins.
Published when an accepted order is amended
orderIdstring uuidRequiredrevisionintegerRequired2changedFieldsarray of stringRequired1Unique itemsitemsdeliveryAddressdeliveryMethodpromotionCodepreviousTotalintegerRequired0newTotalintegerRequired0currencystringRequired^[A-Z]{3}$amendedBystringRequiredCustomer, support agent, or automated policy identifier
reasonstring250amendedAtstring date-timeRequiredOverview
OrderAmended records an approved change to an order, such as a quantity adjustment, delivery method change, or promotional correction. Consumers use the revision and changed fields to update projections without rebuilding the full order history.
Nothing in the catalog.
{
"orderId": "7e86e1d8-cd5f-4d6f-ae8e-bdc5ed3a0d13",
"revision": 2,
"changedFields": [
"items",
"promotionCode"
],
"previousTotal": 12999,
"newTotal": 11999,
"currency": "GBP",
"amendedBy": "support-agent:maya.chen",
"reason": "Removed duplicate accessory and applied verified welcome offer",
"amendedAt": "2026-07-29T09:48:03Z"
}/** Published when an accepted order is amended */
export interface OrderAmended {
orderId: string;
revision: number;
changedFields: ("items" | "deliveryAddress" | "deliveryMethod" | "promotionCode")[];
previousTotal: number;
newTotal: number;
currency: string;
/** Customer, support agent, or automated policy identifier */
amendedBy: string;
reason?: string;
amendedAt: string;
}{
"$schema": "http://json-schema.org/draft-07/schema#",
"title": "OrderAmended",
"description": "Published when an accepted order is amended",
"type": "object",
"properties": {
"orderId": {
"type": "string",
"format": "uuid"
},
"revision": {
"type": "integer",
"minimum": 2
},
"changedFields": {
"type": "array",
"items": {
"type": "string",
"enum": [
"items",
"deliveryAddress",
"deliveryMethod",
"promotionCode"
]
},
"minItems": 1,
"uniqueItems": true
},
"previousTotal": {
"type": "integer",
"minimum": 0
},
"newTotal": {
"type": "integer",
"minimum": 0
},
"currency": {
"type": "string",
"pattern": "^[A-Z]{3}$"
},
"amendedBy": {
"type": "string",
"description": "Customer, support agent, or automated policy identifier"
},
"reason": {
"type": "string",
"maxLength": 250
},
"amendedAt": {
"type": "string",
"format": "date-time"
}
},
"required": [
"orderId",
"revision",
"changedFields",
"previousTotal",
"newTotal",
"currency",
"amendedBy",
"amendedAt"
],
"examples": [
{
"orderId": "7e86e1d8-cd5f-4d6f-ae8e-bdc5ed3a0d13",
"revision": 2,
"changedFields": [
"items",
"promotionCode"
],
"previousTotal": 12999,
"newTotal": 11999,
"currency": "GBP",
"amendedBy": "support-agent:maya.chen",
"reason": "Removed duplicate accessory and applied verified welcome offer",
"amendedAt": "2026-07-29T09:48:03Z"
}
]
}Order Archived
EVTv1.0.0Broker:KafkaPublished when a terminal order is moved from operational storage to the long-term archive.
Published when a terminal order is moved to long-term storage
orderIdstring uuidRequiredterminalStatusstringRequiredCOMPLETEDCANCELLEDretentionCategorystringRequiredSTANDARDFINANCIAL_RECORDLEGAL_HOLDarchiveReferencestringRequiredrecordChecksumstringRequired^[a-f0-9]{64}$terminalAtstring date-timeRequiredarchivedAtstring date-timeRequiredOverview
OrderArchived marks the end of the operational retention period for a completed or cancelled order. Reporting, compliance, and support systems use the archive reference to locate historical data after it leaves the primary order database.
Nothing in the catalog.
{
"orderId": "7e86e1d8-cd5f-4d6f-ae8e-bdc5ed3a0d13",
"terminalStatus": "COMPLETED",
"retentionCategory": "FINANCIAL_RECORD",
"archiveReference": "orders/2026/07/7e86e1d8-cd5f-4d6f-ae8e-bdc5ed3a0d13.json",
"recordChecksum": "a948904f2f0f479b8f8197694b30184b0d2ed1c1cd2a1ec0fb85d299a192a447",
"terminalAt": "2026-08-01T14:22:09Z",
"archivedAt": "2033-08-01T02:15:00Z"
}/** Published when a terminal order is moved to long-term storage */
export interface OrderArchived {
orderId: string;
terminalStatus: "COMPLETED" | "CANCELLED";
retentionCategory: "STANDARD" | "FINANCIAL_RECORD" | "LEGAL_HOLD";
archiveReference: string;
recordChecksum: string;
terminalAt: string;
archivedAt: string;
}{
"$schema": "http://json-schema.org/draft-07/schema#",
"title": "OrderArchived",
"description": "Published when a terminal order is moved to long-term storage",
"type": "object",
"properties": {
"orderId": {
"type": "string",
"format": "uuid"
},
"terminalStatus": {
"type": "string",
"enum": [
"COMPLETED",
"CANCELLED"
]
},
"retentionCategory": {
"type": "string",
"enum": [
"STANDARD",
"FINANCIAL_RECORD",
"LEGAL_HOLD"
]
},
"archiveReference": {
"type": "string"
},
"recordChecksum": {
"type": "string",
"pattern": "^[a-f0-9]{64}$"
},
"terminalAt": {
"type": "string",
"format": "date-time"
},
"archivedAt": {
"type": "string",
"format": "date-time"
}
},
"required": [
"orderId",
"terminalStatus",
"retentionCategory",
"archiveReference",
"recordChecksum",
"terminalAt",
"archivedAt"
],
"examples": [
{
"orderId": "7e86e1d8-cd5f-4d6f-ae8e-bdc5ed3a0d13",
"terminalStatus": "COMPLETED",
"retentionCategory": "FINANCIAL_RECORD",
"archiveReference": "orders/2026/07/7e86e1d8-cd5f-4d6f-ae8e-bdc5ed3a0d13.json",
"recordChecksum": "a948904f2f0f479b8f8197694b30184b0d2ed1c1cd2a1ec0fb85d299a192a447",
"terminalAt": "2026-08-01T14:22:09Z",
"archivedAt": "2033-08-01T02:15:00Z"
}
]
}Order Cancelled
EVTv1.0.0Broker:KafkaPublished when an order has been cancelled.
Published when an order has been cancelled
orderIdstring uuidRequiredcustomerIdstring uuidreasonstringRequiredCUSTOMER_REQUESTEDPAYMENT_FAILEDOUT_OF_STOCKFRAUDcancelledAtstring date-timeRequiredOverview
OrderCancelled is published by the Order Service when an order is cancelled — whether at the customer's request or because a downstream step (payment, inventory) failed. Downstream systems consume it to release inventory, refund or void payment, and stop fulfilment.
{
"orderId": "3f6b2b8e-9a4c-4f0e-8f2a-1c2d3e4f5a6b",
"customerId": "3f6b2b8e-9a4c-4f0e-8f2a-1c2d3e4f5a6b",
"reason": "CUSTOMER_REQUESTED",
"cancelledAt": "2026-01-01T12:00:00Z"
}/** Published when an order has been cancelled */
export interface OrderCancelled {
orderId: string;
customerId?: string;
reason: "CUSTOMER_REQUESTED" | "PAYMENT_FAILED" | "OUT_OF_STOCK" | "FRAUD";
cancelledAt: string;
}{
"$schema": "http://json-schema.org/draft-07/schema#",
"title": "OrderCancelled",
"description": "Published when an order has been cancelled",
"type": "object",
"properties": {
"orderId": {
"type": "string",
"format": "uuid"
},
"customerId": {
"type": "string",
"format": "uuid"
},
"reason": {
"type": "string",
"enum": [
"CUSTOMER_REQUESTED",
"PAYMENT_FAILED",
"OUT_OF_STOCK",
"FRAUD"
]
},
"cancelledAt": {
"type": "string",
"format": "date-time"
}
},
"required": [
"orderId",
"reason",
"cancelledAt"
]
}Order Completed
EVTv1.0.0Broker:KafkaPublished when an order has been fulfilled and completed.
Published when an order has been fulfilled and completed
orderIdstring uuidRequiredcustomerIdstring uuidRequiredcompletedAtstring date-timeRequiredOverview
OrderCompleted is published by the Order Service when an order has been fully fulfilled. It marks the end of the happy path for an order. Downstream systems consume it to close out fulfilment, capture payment, and update reporting.
{
"orderId": "3f6b2b8e-9a4c-4f0e-8f2a-1c2d3e4f5a6b",
"customerId": "3f6b2b8e-9a4c-4f0e-8f2a-1c2d3e4f5a6b",
"completedAt": "2026-01-01T12:00:00Z"
}/** Published when an order has been fulfilled and completed */
export interface OrderCompleted {
orderId: string;
customerId: string;
completedAt: string;
}{
"$schema": "http://json-schema.org/draft-07/schema#",
"title": "OrderCompleted",
"description": "Published when an order has been fulfilled and completed",
"type": "object",
"properties": {
"orderId": {
"type": "string",
"format": "uuid"
},
"customerId": {
"type": "string",
"format": "uuid"
},
"completedAt": {
"type": "string",
"format": "date-time"
}
},
"required": [
"orderId",
"customerId",
"completedAt"
]
}Order Confirmed
EVTv1.0.0Broker:KafkaPublished when payment, inventory, and order validation have succeeded and the order is ready for fulfilment.
Published when an order is confirmed and ready for fulfilment
orderIdstring uuidRequiredcustomerIdstring uuidRequiredconfirmationNumberstringRequired^ORD-[0-9]{8}$paymentAuthorizationIdstringinventoryReservationIdstringtotalintegerRequiredConfirmed total in minor units
0currencystringRequired^[A-Z]{3}$confirmedAtstring date-timeRequiredOverview
OrderConfirmed is published by the Order Service once an order has passed validation and its payment and inventory reservations are secured. Fulfilment, customer notification, and analytics consumers use this as the reliable signal that the order can progress.
{
"orderId": "7e86e1d8-cd5f-4d6f-ae8e-bdc5ed3a0d13",
"customerId": "5d1db561-4ce3-4f92-956a-b787c2f55342",
"confirmationNumber": "ORD-10428371",
"paymentAuthorizationId": "pa_9f38c0f0",
"inventoryReservationId": "res_48721",
"total": 12999,
"currency": "GBP",
"confirmedAt": "2026-07-29T09:42:18Z"
}/** Published when an order is confirmed and ready for fulfilment */
export interface OrderConfirmed {
orderId: string;
customerId: string;
confirmationNumber: string;
paymentAuthorizationId?: string;
inventoryReservationId?: string;
/** Confirmed total in minor units */
total: number;
currency: string;
confirmedAt: string;
}{
"$schema": "http://json-schema.org/draft-07/schema#",
"title": "OrderConfirmed",
"description": "Published when an order is confirmed and ready for fulfilment",
"type": "object",
"properties": {
"orderId": {
"type": "string",
"format": "uuid"
},
"customerId": {
"type": "string",
"format": "uuid"
},
"confirmationNumber": {
"type": "string",
"pattern": "^ORD-[0-9]{8}$"
},
"paymentAuthorizationId": {
"type": "string"
},
"inventoryReservationId": {
"type": "string"
},
"total": {
"type": "integer",
"minimum": 0,
"description": "Confirmed total in minor units"
},
"currency": {
"type": "string",
"pattern": "^[A-Z]{3}$"
},
"confirmedAt": {
"type": "string",
"format": "date-time"
}
},
"required": [
"orderId",
"customerId",
"confirmationNumber",
"total",
"currency",
"confirmedAt"
],
"examples": [
{
"orderId": "7e86e1d8-cd5f-4d6f-ae8e-bdc5ed3a0d13",
"customerId": "5d1db561-4ce3-4f92-956a-b787c2f55342",
"confirmationNumber": "ORD-10428371",
"paymentAuthorizationId": "pa_9f38c0f0",
"inventoryReservationId": "res_48721",
"total": 12999,
"currency": "GBP",
"confirmedAt": "2026-07-29T09:42:18Z"
}
]
}Order Created
EVTv1.0.0Broker:KafkaPublished when a new order has been created.
Published when a new order has been created
orderIdstring uuidRequiredcustomerIdstring uuidRequiredtotalintegerRequiredOrder total in minor units (e.g. cents)
currencystringRequired^[A-Z]{3}$statusstringRequiredInitial lifecycle status for the order
createditemsarray of objectRequiredLine items captured at order creation time
skustringRequiredquantityintegerRequired1unitPriceintegerRequiredUnit price in minor units (e.g. cents)
createdAtstring date-timeRequiredOverview
OrderCreated is published by the Order Service when a new order is created from a checked-out cart. Downstream systems consume this event to begin fulfilment, send confirmation to the customer, and update reporting.
Nothing in the catalog.
{
"orderId": "3f6b2b8e-9a4c-4f0e-8f2a-1c2d3e4f5a6b",
"customerId": "3f6b2b8e-9a4c-4f0e-8f2a-1c2d3e4f5a6b",
"total": 0,
"currency": "string",
"status": "created",
"items": [
{
"sku": "string",
"quantity": 1,
"unitPrice": 0
}
],
"createdAt": "2026-01-01T12:00:00Z"
}/** Published when a new order has been created */
export interface OrderCreated {
orderId: string;
customerId: string;
/** Order total in minor units (e.g. cents) */
total: number;
currency: string;
/** Initial lifecycle status for the order */
status: "created";
/** Line items captured at order creation time */
items: {
sku: string;
quantity: number;
/** Unit price in minor units (e.g. cents) */
unitPrice: number;
}[];
createdAt: string;
}{
"$schema": "http://json-schema.org/draft-07/schema#",
"title": "OrderCreated",
"description": "Published when a new order has been created",
"type": "object",
"properties": {
"orderId": {
"type": "string",
"format": "uuid"
},
"customerId": {
"type": "string",
"format": "uuid"
},
"total": {
"type": "integer",
"description": "Order total in minor units (e.g. cents)"
},
"currency": {
"type": "string",
"pattern": "^[A-Z]{3}$"
},
"status": {
"type": "string",
"enum": [
"created"
],
"description": "Initial lifecycle status for the order"
},
"items": {
"type": "array",
"description": "Line items captured at order creation time",
"items": {
"type": "object",
"properties": {
"sku": {
"type": "string"
},
"quantity": {
"type": "integer",
"minimum": 1
},
"unitPrice": {
"type": "integer",
"description": "Unit price in minor units (e.g. cents)"
}
},
"required": [
"sku",
"quantity",
"unitPrice"
]
}
},
"createdAt": {
"type": "string",
"format": "date-time"
}
},
"required": [
"orderId",
"customerId",
"total",
"currency",
"status",
"items",
"createdAt"
]
}Order Delivery Address Changed
EVTv1.0.0Broker:KafkaPublished when the validated delivery address changes before dispatch.
Published when the validated delivery address for an order changes
orderIdstring uuidRequiredaddressRevisionintegerRequired2previousPostalCodestringRequireddeliveryAddressobjectRequiredrecipientNamestringRequiredline1stringRequiredline2stringcitystringRequiredpostalCodestringRequiredcountryCodestringRequired^[A-Z]{2}$changedBystringRequiredchangedAtstring date-timeRequiredOverview
OrderDeliveryAddressChanged provides fulfilment and carrier integrations with the latest validated delivery destination. The previous postal code and revision make stale updates detectable without exposing unnecessary customer details.
Nothing in the catalog.
{
"orderId": "7e86e1d8-cd5f-4d6f-ae8e-bdc5ed3a0d13",
"addressRevision": 2,
"previousPostalCode": "SW1A 1AA",
"deliveryAddress": {
"recipientName": "Alex Morgan",
"line1": "18 Market Street",
"line2": "Apartment 4B",
"city": "London",
"postalCode": "E1 6AN",
"countryCode": "GB"
},
"changedBy": "customer:5d1db561-4ce3-4f92-956a-b787c2f55342",
"changedAt": "2026-07-29T09:46:41Z"
}/** Published when the validated delivery address for an order changes */
export interface OrderDeliveryAddressChanged {
orderId: string;
addressRevision: number;
previousPostalCode: string;
deliveryAddress: {
recipientName: string;
line1: string;
line2?: string;
city: string;
postalCode: string;
countryCode: string;
};
changedBy: string;
changedAt: string;
}{
"$schema": "http://json-schema.org/draft-07/schema#",
"title": "OrderDeliveryAddressChanged",
"description": "Published when the validated delivery address for an order changes",
"type": "object",
"properties": {
"orderId": {
"type": "string",
"format": "uuid"
},
"addressRevision": {
"type": "integer",
"minimum": 2
},
"previousPostalCode": {
"type": "string"
},
"deliveryAddress": {
"type": "object",
"properties": {
"recipientName": {
"type": "string"
},
"line1": {
"type": "string"
},
"line2": {
"type": "string"
},
"city": {
"type": "string"
},
"postalCode": {
"type": "string"
},
"countryCode": {
"type": "string",
"pattern": "^[A-Z]{2}$"
}
},
"required": [
"recipientName",
"line1",
"city",
"postalCode",
"countryCode"
]
},
"changedBy": {
"type": "string"
},
"changedAt": {
"type": "string",
"format": "date-time"
}
},
"required": [
"orderId",
"addressRevision",
"previousPostalCode",
"deliveryAddress",
"changedBy",
"changedAt"
],
"examples": [
{
"orderId": "7e86e1d8-cd5f-4d6f-ae8e-bdc5ed3a0d13",
"addressRevision": 2,
"previousPostalCode": "SW1A 1AA",
"deliveryAddress": {
"recipientName": "Alex Morgan",
"line1": "18 Market Street",
"line2": "Apartment 4B",
"city": "London",
"postalCode": "E1 6AN",
"countryCode": "GB"
},
"changedBy": "customer:5d1db561-4ce3-4f92-956a-b787c2f55342",
"changedAt": "2026-07-29T09:46:41Z"
}
]
}Order Fulfilment Started
EVTv1.0.0Broker:KafkaPublished when an order is released to a fulfilment location for picking and packing.
Published when an order is released for picking and packing
orderIdstring uuidRequiredfulfilmentIdstring uuidRequiredwarehouseIdstringRequireditemCountintegerRequired1prioritystringRequiredSTANDARDEXPEDITEDSAME_DAYdeliveryMethodstringRequiredHOME_DELIVERYCLICK_AND_COLLECTestimatedDispatchAtstring date-timestartedAtstring date-timeRequiredOverview
OrderFulfilmentStarted marks the handoff from order management to warehouse execution. Customer communications use it to update delivery expectations, while analytics consumers measure the time from confirmation to operational fulfilment.
Nothing in the catalog.
{
"orderId": "7e86e1d8-cd5f-4d6f-ae8e-bdc5ed3a0d13",
"fulfilmentId": "65c36d91-fe6c-4ea1-bc4c-95e73afece2b",
"warehouseId": "wh-london-02",
"itemCount": 3,
"priority": "EXPEDITED",
"deliveryMethod": "HOME_DELIVERY",
"estimatedDispatchAt": "2026-07-29T16:30:00Z",
"startedAt": "2026-07-29T10:06:12Z"
}/** Published when an order is released for picking and packing */
export interface OrderFulfilmentStarted {
orderId: string;
fulfilmentId: string;
warehouseId: string;
itemCount: number;
priority: "STANDARD" | "EXPEDITED" | "SAME_DAY";
deliveryMethod: "HOME_DELIVERY" | "CLICK_AND_COLLECT";
estimatedDispatchAt?: string;
startedAt: string;
}{
"$schema": "http://json-schema.org/draft-07/schema#",
"title": "OrderFulfilmentStarted",
"description": "Published when an order is released for picking and packing",
"type": "object",
"properties": {
"orderId": {
"type": "string",
"format": "uuid"
},
"fulfilmentId": {
"type": "string",
"format": "uuid"
},
"warehouseId": {
"type": "string"
},
"itemCount": {
"type": "integer",
"minimum": 1
},
"priority": {
"type": "string",
"enum": [
"STANDARD",
"EXPEDITED",
"SAME_DAY"
]
},
"deliveryMethod": {
"type": "string",
"enum": [
"HOME_DELIVERY",
"CLICK_AND_COLLECT"
]
},
"estimatedDispatchAt": {
"type": "string",
"format": "date-time"
},
"startedAt": {
"type": "string",
"format": "date-time"
}
},
"required": [
"orderId",
"fulfilmentId",
"warehouseId",
"itemCount",
"priority",
"deliveryMethod",
"startedAt"
],
"examples": [
{
"orderId": "7e86e1d8-cd5f-4d6f-ae8e-bdc5ed3a0d13",
"fulfilmentId": "65c36d91-fe6c-4ea1-bc4c-95e73afece2b",
"warehouseId": "wh-london-02",
"itemCount": 3,
"priority": "EXPEDITED",
"deliveryMethod": "HOME_DELIVERY",
"estimatedDispatchAt": "2026-07-29T16:30:00Z",
"startedAt": "2026-07-29T10:06:12Z"
}
]
}Order Hold Released
EVTv1.0.0Broker:KafkaPublished when an operational hold is resolved and the order can continue.
Published when an operational hold on an order is released
orderIdstring uuidRequiredholdIdstring uuidRequiredpreviousReasonstringRequiredPAYMENT_REVIEWFRAUD_REVIEWADDRESS_VERIFICATIONINVENTORY_RECHECKresolutionstringRequired250releasedBystringRequirednextStatusstringRequiredCONFIRMEDAWAITING_FULFILMENTreleasedAtstring date-timeRequiredOverview
OrderHoldReleased resumes processing after the concern represented by an order hold has been resolved. The event correlates to the original hold and records the resolution for support, audit, and fulfilment consumers.
Nothing in the catalog.
{
"orderId": "7e86e1d8-cd5f-4d6f-ae8e-bdc5ed3a0d13",
"holdId": "49c81188-c99a-4af4-97c9-2e9516bba8f7",
"previousReason": "ADDRESS_VERIFICATION",
"resolution": "Postal address matched the carrier validation service",
"releasedBy": "address-verification-policy:v3",
"nextStatus": "AWAITING_FULFILMENT",
"releasedAt": "2026-07-29T10:04:51Z"
}/** Published when an operational hold on an order is released */
export interface OrderHoldReleased {
orderId: string;
holdId: string;
previousReason: "PAYMENT_REVIEW" | "FRAUD_REVIEW" | "ADDRESS_VERIFICATION" | "INVENTORY_RECHECK";
resolution: string;
releasedBy: string;
nextStatus: "CONFIRMED" | "AWAITING_FULFILMENT";
releasedAt: string;
}{
"$schema": "http://json-schema.org/draft-07/schema#",
"title": "OrderHoldReleased",
"description": "Published when an operational hold on an order is released",
"type": "object",
"properties": {
"orderId": {
"type": "string",
"format": "uuid"
},
"holdId": {
"type": "string",
"format": "uuid"
},
"previousReason": {
"type": "string",
"enum": [
"PAYMENT_REVIEW",
"FRAUD_REVIEW",
"ADDRESS_VERIFICATION",
"INVENTORY_RECHECK"
]
},
"resolution": {
"type": "string",
"maxLength": 250
},
"releasedBy": {
"type": "string"
},
"nextStatus": {
"type": "string",
"enum": [
"CONFIRMED",
"AWAITING_FULFILMENT"
]
},
"releasedAt": {
"type": "string",
"format": "date-time"
}
},
"required": [
"orderId",
"holdId",
"previousReason",
"resolution",
"releasedBy",
"nextStatus",
"releasedAt"
],
"examples": [
{
"orderId": "7e86e1d8-cd5f-4d6f-ae8e-bdc5ed3a0d13",
"holdId": "49c81188-c99a-4af4-97c9-2e9516bba8f7",
"previousReason": "ADDRESS_VERIFICATION",
"resolution": "Postal address matched the carrier validation service",
"releasedBy": "address-verification-policy:v3",
"nextStatus": "AWAITING_FULFILMENT",
"releasedAt": "2026-07-29T10:04:51Z"
}
]
}Order Packed
EVTv1.0.0Broker:KafkaPublished when an order has been picked and packed in the warehouse.
Published when an order has been picked and packed in the warehouse
orderIdstring uuidRequiredpickingJobIdstring uuidparcelCountinteger1packedAtstring date-timeRequiredOverview
OrderPacked is published by the Picking Worker when an order has been fully picked and packed. The Warehouse Service consumes it to mark the order ready and publish Order Ready For Shipping.
{
"orderId": "3f6b2b8e-9a4c-4f0e-8f2a-1c2d3e4f5a6b",
"pickingJobId": "3f6b2b8e-9a4c-4f0e-8f2a-1c2d3e4f5a6b",
"parcelCount": 1,
"packedAt": "2026-01-01T12:00:00Z"
}/** Published when an order has been picked and packed in the warehouse */
export interface OrderPacked {
orderId: string;
pickingJobId?: string;
parcelCount?: number;
packedAt: string;
}{
"$schema": "http://json-schema.org/draft-07/schema#",
"title": "OrderPacked",
"description": "Published when an order has been picked and packed in the warehouse",
"type": "object",
"properties": {
"orderId": {
"type": "string",
"format": "uuid"
},
"pickingJobId": {
"type": "string",
"format": "uuid"
},
"parcelCount": {
"type": "integer",
"minimum": 1
},
"packedAt": {
"type": "string",
"format": "date-time"
}
},
"required": [
"orderId",
"packedAt"
]
}Order Placed On Hold
EVTv1.0.0Broker:KafkaPublished when order progression is paused for a review or dependency check.
Published when an order is paused for operational review
orderIdstring uuidRequiredholdIdstring uuidRequiredreasonstringRequiredPAYMENT_REVIEWFRAUD_REVIEWADDRESS_VERIFICATIONINVENTORY_RECHECKownerTeamstringRequiredcustomerMessagestring280reviewBystring date-timeRequiredplacedAtstring date-timeRequiredOverview
OrderPlacedOnHold tells fulfilment and customer-facing systems to pause work while a payment, fraud, address, or inventory concern is reviewed. It includes the owning team and review deadline so operational tooling can route and escalate the hold.
Nothing in the catalog.
{
"orderId": "7e86e1d8-cd5f-4d6f-ae8e-bdc5ed3a0d13",
"holdId": "49c81188-c99a-4af4-97c9-2e9516bba8f7",
"reason": "ADDRESS_VERIFICATION",
"ownerTeam": "ordering-operations",
"customerMessage": "We are confirming one detail of your delivery address. No action is required yet.",
"reviewBy": "2026-07-29T11:00:00Z",
"placedAt": "2026-07-29T09:51:26Z"
}/** Published when an order is paused for operational review */
export interface OrderPlacedOnHold {
orderId: string;
holdId: string;
reason: "PAYMENT_REVIEW" | "FRAUD_REVIEW" | "ADDRESS_VERIFICATION" | "INVENTORY_RECHECK";
ownerTeam: string;
customerMessage?: string;
reviewBy: string;
placedAt: string;
}{
"$schema": "http://json-schema.org/draft-07/schema#",
"title": "OrderPlacedOnHold",
"description": "Published when an order is paused for operational review",
"type": "object",
"properties": {
"orderId": {
"type": "string",
"format": "uuid"
},
"holdId": {
"type": "string",
"format": "uuid"
},
"reason": {
"type": "string",
"enum": [
"PAYMENT_REVIEW",
"FRAUD_REVIEW",
"ADDRESS_VERIFICATION",
"INVENTORY_RECHECK"
]
},
"ownerTeam": {
"type": "string"
},
"customerMessage": {
"type": "string",
"maxLength": 280
},
"reviewBy": {
"type": "string",
"format": "date-time"
},
"placedAt": {
"type": "string",
"format": "date-time"
}
},
"required": [
"orderId",
"holdId",
"reason",
"ownerTeam",
"reviewBy",
"placedAt"
],
"examples": [
{
"orderId": "7e86e1d8-cd5f-4d6f-ae8e-bdc5ed3a0d13",
"holdId": "49c81188-c99a-4af4-97c9-2e9516bba8f7",
"reason": "ADDRESS_VERIFICATION",
"ownerTeam": "ordering-operations",
"customerMessage": "We are confirming one detail of your delivery address. No action is required yet.",
"reviewBy": "2026-07-29T11:00:00Z",
"placedAt": "2026-07-29T09:51:26Z"
}
]
}Order Ready For Shipping
EVTv1.0.0Broker:KafkaPublished when a packed order is ready to be handed to a carrier for shipping.
Published when a packed order is ready to be handed to a carrier
orderIdstring uuidRequiredcustomerIdstring uuidparcelCountinteger1shippingAddressobjectRequiredline1stringRequiredcitystringRequiredpostcodestringRequiredcountrystringRequired^[A-Z]{2}$readyAtstring date-timeRequiredOverview
OrderReadyForShipping is published by the Warehouse Service once an order has been packed. The Shipping System consumes it to create a shipment with a carrier.
{
"orderId": "3f6b2b8e-9a4c-4f0e-8f2a-1c2d3e4f5a6b",
"customerId": "3f6b2b8e-9a4c-4f0e-8f2a-1c2d3e4f5a6b",
"parcelCount": 1,
"shippingAddress": {
"line1": "string",
"city": "string",
"postcode": "string",
"country": "string"
},
"readyAt": "2026-01-01T12:00:00Z"
}/** Published when a packed order is ready to be handed to a carrier */
export interface OrderReadyForShipping {
orderId: string;
customerId?: string;
parcelCount?: number;
shippingAddress: {
line1: string;
city: string;
postcode: string;
country: string;
};
readyAt: string;
}{
"$schema": "http://json-schema.org/draft-07/schema#",
"title": "OrderReadyForShipping",
"description": "Published when a packed order is ready to be handed to a carrier",
"type": "object",
"properties": {
"orderId": {
"type": "string",
"format": "uuid"
},
"customerId": {
"type": "string",
"format": "uuid"
},
"parcelCount": {
"type": "integer",
"minimum": 1
},
"shippingAddress": {
"type": "object",
"properties": {
"line1": {
"type": "string"
},
"city": {
"type": "string"
},
"postcode": {
"type": "string"
},
"country": {
"type": "string",
"pattern": "^[A-Z]{2}$"
}
},
"required": [
"line1",
"city",
"postcode",
"country"
]
},
"readyAt": {
"type": "string",
"format": "date-time"
}
},
"required": [
"orderId",
"shippingAddress",
"readyAt"
]
}Order Status Changed
EVTv1.0.0Broker:KafkaPublished for every accepted transition in the order lifecycle state machine.
Published for every accepted order lifecycle transition
orderIdstring uuidRequiredpreviousStatusstringRequiredCREATEDCONFIRMEDON_HOLDAWAITING_FULFILMENTFULFILLINGCOMPLETEDCANCELLEDnewStatusstringRequiredCONFIRMEDON_HOLDAWAITING_FULFILMENTFULFILLINGCOMPLETEDCANCELLEDARCHIVEDsequenceintegerRequiredMonotonic transition number for the order
1changeReasonstring250correlationIdstring uuidchangedAtstring date-timeRequiredOverview
OrderStatusChanged is the canonical state-transition event for projections and operational timelines. More specific business events remain the preferred integration points, while this event supports generic history, search, support, and analytics use cases.
Nothing in the catalog.
{
"orderId": "7e86e1d8-cd5f-4d6f-ae8e-bdc5ed3a0d13",
"previousStatus": "AWAITING_FULFILMENT",
"newStatus": "FULFILLING",
"sequence": 5,
"changeReason": "Released to warehouse wh-london-02",
"correlationId": "896f860b-aea5-4b98-91c5-ef4d188778dd",
"changedAt": "2026-07-29T10:06:12Z"
}/** Published for every accepted order lifecycle transition */
export interface OrderStatusChanged {
orderId: string;
previousStatus: "CREATED" | "CONFIRMED" | "ON_HOLD" | "AWAITING_FULFILMENT" | "FULFILLING" | "COMPLETED" | "CANCELLED";
newStatus: "CONFIRMED" | "ON_HOLD" | "AWAITING_FULFILMENT" | "FULFILLING" | "COMPLETED" | "CANCELLED" | "ARCHIVED";
/** Monotonic transition number for the order */
sequence: number;
changeReason?: string;
correlationId?: string;
changedAt: string;
}{
"$schema": "http://json-schema.org/draft-07/schema#",
"title": "OrderStatusChanged",
"description": "Published for every accepted order lifecycle transition",
"type": "object",
"properties": {
"orderId": {
"type": "string",
"format": "uuid"
},
"previousStatus": {
"type": "string",
"enum": [
"CREATED",
"CONFIRMED",
"ON_HOLD",
"AWAITING_FULFILMENT",
"FULFILLING",
"COMPLETED",
"CANCELLED"
]
},
"newStatus": {
"type": "string",
"enum": [
"CONFIRMED",
"ON_HOLD",
"AWAITING_FULFILMENT",
"FULFILLING",
"COMPLETED",
"CANCELLED",
"ARCHIVED"
]
},
"sequence": {
"type": "integer",
"minimum": 1,
"description": "Monotonic transition number for the order"
},
"changeReason": {
"type": "string",
"maxLength": 250
},
"correlationId": {
"type": "string",
"format": "uuid"
},
"changedAt": {
"type": "string",
"format": "date-time"
}
},
"required": [
"orderId",
"previousStatus",
"newStatus",
"sequence",
"changedAt"
],
"examples": [
{
"orderId": "7e86e1d8-cd5f-4d6f-ae8e-bdc5ed3a0d13",
"previousStatus": "AWAITING_FULFILMENT",
"newStatus": "FULFILLING",
"sequence": 5,
"changeReason": "Released to warehouse wh-london-02",
"correlationId": "896f860b-aea5-4b98-91c5-ef4d188778dd",
"changedAt": "2026-07-29T10:06:12Z"
}
]
}Payment Failed
EVTv1.0.0Broker:KafkaPublished by Stripe when a charge fails.
Published when a charge fails
paymentIdstring uuidRequiredorderIdstring uuidRequiredreasonstringRequiredCARD_DECLINEDINSUFFICIENT_FUNDSEXPIRED_CARDPROCESSING_ERRORfailedAtstring date-timeRequiredOverview
PaymentFailed is delivered by Stripe's Webhook Endpoint when a requested charge fails — for example a declined card. The Payment Worker consumes it and records the payment as failed, which ultimately leads the order to be cancelled.
{
"paymentId": "3f6b2b8e-9a4c-4f0e-8f2a-1c2d3e4f5a6b",
"orderId": "3f6b2b8e-9a4c-4f0e-8f2a-1c2d3e4f5a6b",
"reason": "CARD_DECLINED",
"failedAt": "2026-01-01T12:00:00Z"
}/** Published when a charge fails */
export interface PaymentFailed {
paymentId: string;
orderId: string;
reason: "CARD_DECLINED" | "INSUFFICIENT_FUNDS" | "EXPIRED_CARD" | "PROCESSING_ERROR";
failedAt: string;
}{
"$schema": "http://json-schema.org/draft-07/schema#",
"title": "PaymentFailed",
"description": "Published when a charge fails",
"type": "object",
"properties": {
"paymentId": {
"type": "string",
"format": "uuid"
},
"orderId": {
"type": "string",
"format": "uuid"
},
"reason": {
"type": "string",
"enum": [
"CARD_DECLINED",
"INSUFFICIENT_FUNDS",
"EXPIRED_CARD",
"PROCESSING_ERROR"
]
},
"failedAt": {
"type": "string",
"format": "date-time"
}
},
"required": [
"paymentId",
"orderId",
"reason",
"failedAt"
]
}Payment Requested
EVTv1.0.0Broker:KafkaPublished when the Payment Processing System requests a charge from the payment processor.
Published when a charge is requested from the payment processor
paymentIdstring uuidRequiredorderIdstring uuidRequiredpayeroneOfRequiredThe user or customer account responsible for the payment
userIdstring uuidRequiredThe authenticated user requesting the payment
emailstring emailRequiredThe contact email shared by both payer types
customerIdstring uuidRequiredThe customer account requesting the payment
emailstring emailRequiredThe contact email shared by both payer types
amountintegerRequiredAmount to charge, in minor units (e.g. cents)
0currencystringRequired^[A-Z]{3}$requestedAtstring date-timeRequiredOverview
PaymentRequested is published by the Payment Worker to ask the external Stripe to charge a customer for an order. Stripe responds with Payment Succeeded or Payment Failed. The Fraud Detection system also consumes this event to screen the payment.
{
"paymentId": "3f6b2b8e-9a4c-4f0e-8f2a-1c2d3e4f5a6b",
"orderId": "3f6b2b8e-9a4c-4f0e-8f2a-1c2d3e4f5a6b",
"payer": {
"userId": "3f6b2b8e-9a4c-4f0e-8f2a-1c2d3e4f5a6b",
"email": "jane@example.com"
},
"amount": 0,
"currency": "string",
"requestedAt": "2026-01-01T12:00:00Z"
}/** Published when a charge is requested from the payment processor */
export interface PaymentRequested {
paymentId: string;
orderId: string;
/** The user or customer account responsible for the payment */
payer: {
/** The authenticated user requesting the payment */
userId: string;
/** The contact email shared by both payer types */
email: string;
} | {
/** The customer account requesting the payment */
customerId: string;
/** The contact email shared by both payer types */
email: string;
};
/** Amount to charge, in minor units (e.g. cents) */
amount: number;
currency: string;
requestedAt: string;
}{
"$schema": "http://json-schema.org/draft-07/schema#",
"title": "PaymentRequested",
"description": "Published when a charge is requested from the payment processor",
"type": "object",
"properties": {
"paymentId": {
"type": "string",
"format": "uuid"
},
"orderId": {
"type": "string",
"format": "uuid"
},
"payer": {
"type": "object",
"description": "The user or customer account responsible for the payment",
"additionalProperties": false,
"properties": {
"userId": {
"type": "string",
"format": "uuid",
"description": "The authenticated user requesting the payment"
},
"customerId": {
"type": "string",
"format": "uuid",
"description": "The customer account requesting the payment"
},
"email": {
"type": "string",
"format": "email",
"description": "The contact email shared by both payer types"
}
},
"required": [
"email"
],
"oneOf": [
{
"title": "Authenticated user",
"required": [
"userId"
],
"not": {
"required": [
"customerId"
]
}
},
{
"title": "Customer account",
"required": [
"customerId"
],
"not": {
"required": [
"userId"
]
}
}
]
},
"amount": {
"type": "integer",
"minimum": 0,
"description": "Amount to charge, in minor units (e.g. cents)"
},
"currency": {
"type": "string",
"pattern": "^[A-Z]{3}$"
},
"requestedAt": {
"type": "string",
"format": "date-time"
}
},
"required": [
"paymentId",
"orderId",
"payer",
"amount",
"currency",
"requestedAt"
]
}Payment Succeeded
EVTv1.0.0Broker:KafkaPublished by Stripe when a charge succeeds.
Published when a charge succeeds
paymentIdstring uuidRequiredorderIdstring uuidRequiredamountintegerRequiredAmount charged, in minor units (e.g. cents)
currencystringRequired^[A-Z]{3}$processorReferencestringStripe's charge identifier
succeededAtstring date-timeRequiredOverview
PaymentSucceeded is delivered by Stripe's Webhook Endpoint when a requested charge succeeds. The Payment Worker consumes it and records the payment as succeeded.
{
"paymentId": "3f6b2b8e-9a4c-4f0e-8f2a-1c2d3e4f5a6b",
"orderId": "3f6b2b8e-9a4c-4f0e-8f2a-1c2d3e4f5a6b",
"amount": 0,
"currency": "string",
"processorReference": "string",
"succeededAt": "2026-01-01T12:00:00Z"
}/** Published when a charge succeeds */
export interface PaymentSucceeded {
paymentId: string;
orderId: string;
/** Amount charged, in minor units (e.g. cents) */
amount: number;
currency: string;
/** Stripe's charge identifier */
processorReference?: string;
succeededAt: string;
}{
"$schema": "http://json-schema.org/draft-07/schema#",
"title": "PaymentSucceeded",
"description": "Published when a charge succeeds",
"type": "object",
"properties": {
"paymentId": {
"type": "string",
"format": "uuid"
},
"orderId": {
"type": "string",
"format": "uuid"
},
"amount": {
"type": "integer",
"description": "Amount charged, in minor units (e.g. cents)"
},
"currency": {
"type": "string",
"pattern": "^[A-Z]{3}$"
},
"processorReference": {
"type": "string",
"description": "Stripe's charge identifier"
},
"succeededAt": {
"type": "string",
"format": "date-time"
}
},
"required": [
"paymentId",
"orderId",
"amount",
"currency",
"succeededAt"
]
}Product Created
EVTv1.0.0Broker:KafkaPublished when a new product has been added to the catalog.
Emitted when a new product is added to the catalog
eventIdstring uuidRequiredUnique identifier for this event
occurredAtstring date-timeRequiredTime the product was created
productobjectRequiredThe product that was created
productIdstring uuidRequiredUnique identifier for the product
skustringRequiredStock keeping unit
namestringRequiredDisplay name of the product
descriptionstringLong-form product description
priceintegerRequiredPrice in minor units (e.g. cents)
0currencystringRequiredISO 4217 currency code
^[A-Z]{3}$categorystringCategory the product belongs to
statusstringRequiredLifecycle status of the product
DRAFTACTIVEARCHIVEDOverview
ProductCreated is published by the Product Search Publisher whenever a new product is successfully added to the catalog by the Product API. The Search System consumes this event to index the new product so it becomes discoverable.
{
"eventId": "3f6b2b8e-9a4c-4f0e-8f2a-1c2d3e4f5a6b",
"occurredAt": "2026-01-01T12:00:00Z",
"product": {
"productId": "3f6b2b8e-9a4c-4f0e-8f2a-1c2d3e4f5a6b",
"sku": "string",
"name": "string",
"description": "string",
"price": 0,
"currency": "string",
"category": "string",
"status": "DRAFT"
}
}/** Emitted when a new product is added to the catalog */
export interface ProductCreated {
/** Unique identifier for this event */
eventId: string;
/** Time the product was created */
occurredAt: string;
/** The product that was created */
product: {
/** Unique identifier for the product */
productId: string;
/** Stock keeping unit */
sku: string;
/** Display name of the product */
name: string;
/** Long-form product description */
description?: string;
/** Price in minor units (e.g. cents) */
price: number;
/** ISO 4217 currency code */
currency: string;
/** Category the product belongs to */
category?: string;
/** Lifecycle status of the product */
status: "DRAFT" | "ACTIVE" | "ARCHIVED";
};
}{
"$schema": "http://json-schema.org/draft-07/schema#",
"title": "ProductCreated",
"description": "Emitted when a new product is added to the catalog",
"type": "object",
"properties": {
"eventId": {
"description": "Unique identifier for this event",
"type": "string",
"format": "uuid"
},
"occurredAt": {
"description": "Time the product was created",
"type": "string",
"format": "date-time"
},
"product": {
"description": "The product that was created",
"type": "object",
"properties": {
"productId": {
"description": "Unique identifier for the product",
"type": "string",
"format": "uuid"
},
"sku": {
"description": "Stock keeping unit",
"type": "string"
},
"name": {
"description": "Display name of the product",
"type": "string"
},
"description": {
"description": "Long-form product description",
"type": "string"
},
"price": {
"description": "Price in minor units (e.g. cents)",
"type": "integer",
"minimum": 0
},
"currency": {
"description": "ISO 4217 currency code",
"type": "string",
"pattern": "^[A-Z]{3}$"
},
"category": {
"description": "Category the product belongs to",
"type": "string"
},
"status": {
"description": "Lifecycle status of the product",
"type": "string",
"enum": [
"DRAFT",
"ACTIVE",
"ARCHIVED"
]
}
},
"required": [
"productId",
"sku",
"name",
"price",
"currency",
"status"
]
}
},
"required": [
"eventId",
"occurredAt",
"product"
]
}Product Deleted
EVTv1.0.0Broker:KafkaPublished when a product has been removed from the catalog.
Emitted when a product is removed from the catalog
eventIdstring uuidRequiredUnique identifier for this event
occurredAtstring date-timeRequiredTime the product was deleted
productIdstring uuidRequiredUnique identifier for the product that was deleted
reasonstringOptional reason the product was removed
DISCONTINUEDDUPLICATEMERCHANT_REQUESTOTHEROverview
ProductDeleted is published by the Product Search Publisher when a product is removed from the catalog via the Product API. The Search System consumes this event to remove the product from the search index.
{
"eventId": "3f6b2b8e-9a4c-4f0e-8f2a-1c2d3e4f5a6b",
"occurredAt": "2026-01-01T12:00:00Z",
"productId": "3f6b2b8e-9a4c-4f0e-8f2a-1c2d3e4f5a6b",
"reason": "DISCONTINUED"
}/** Emitted when a product is removed from the catalog */
export interface ProductDeleted {
/** Unique identifier for this event */
eventId: string;
/** Time the product was deleted */
occurredAt: string;
/** Unique identifier for the product that was deleted */
productId: string;
/** Optional reason the product was removed */
reason?: "DISCONTINUED" | "DUPLICATE" | "MERCHANT_REQUEST" | "OTHER";
}{
"$schema": "http://json-schema.org/draft-07/schema#",
"title": "ProductDeleted",
"description": "Emitted when a product is removed from the catalog",
"type": "object",
"properties": {
"eventId": {
"description": "Unique identifier for this event",
"type": "string",
"format": "uuid"
},
"occurredAt": {
"description": "Time the product was deleted",
"type": "string",
"format": "date-time"
},
"productId": {
"description": "Unique identifier for the product that was deleted",
"type": "string",
"format": "uuid"
},
"reason": {
"description": "Optional reason the product was removed",
"type": "string",
"enum": [
"DISCONTINUED",
"DUPLICATE",
"MERCHANT_REQUEST",
"OTHER"
]
}
},
"required": [
"eventId",
"occurredAt",
"productId"
]
}Product Updated
EVTv1.0.0Broker:KafkaPublished when an existing product's data has changed.
Emitted when an existing product's data changes
eventIdstring uuidRequiredUnique identifier for this event
occurredAtstring date-timeRequiredTime the product was updated
productIdstring uuidRequiredUnique identifier for the product that changed
changesobjectRequiredThe fields that changed and their new values
namestringdescriptionstringpriceintegerPrice in minor units (e.g. cents)
0currencystringISO 4217 currency code
^[A-Z]{3}$categorystringstatusstringLifecycle status of the product
DRAFTACTIVEARCHIVEDOverview
ProductUpdated is published by the Product Search Publisher whenever an existing product is changed via the Product API. The Search System consumes this event to re-index the product so search results stay accurate.
{
"eventId": "3f6b2b8e-9a4c-4f0e-8f2a-1c2d3e4f5a6b",
"occurredAt": "2026-01-01T12:00:00Z",
"productId": "3f6b2b8e-9a4c-4f0e-8f2a-1c2d3e4f5a6b",
"changes": {
"name": "string",
"description": "string",
"price": 0,
"currency": "string",
"category": "string",
"status": "DRAFT"
}
}/** Emitted when an existing product's data changes */
export interface ProductUpdated {
/** Unique identifier for this event */
eventId: string;
/** Time the product was updated */
occurredAt: string;
/** Unique identifier for the product that changed */
productId: string;
/** The fields that changed and their new values */
changes: {
name?: string;
description?: string;
/** Price in minor units (e.g. cents) */
price?: number;
/** ISO 4217 currency code */
currency?: string;
category?: string;
/** Lifecycle status of the product */
status?: "DRAFT" | "ACTIVE" | "ARCHIVED";
};
}{
"$schema": "http://json-schema.org/draft-07/schema#",
"title": "ProductUpdated",
"description": "Emitted when an existing product's data changes",
"type": "object",
"properties": {
"eventId": {
"description": "Unique identifier for this event",
"type": "string",
"format": "uuid"
},
"occurredAt": {
"description": "Time the product was updated",
"type": "string",
"format": "date-time"
},
"productId": {
"description": "Unique identifier for the product that changed",
"type": "string",
"format": "uuid"
},
"changes": {
"description": "The fields that changed and their new values",
"type": "object",
"properties": {
"name": {
"type": "string"
},
"description": {
"type": "string"
},
"price": {
"description": "Price in minor units (e.g. cents)",
"type": "integer",
"minimum": 0
},
"currency": {
"description": "ISO 4217 currency code",
"type": "string",
"pattern": "^[A-Z]{3}$"
},
"category": {
"type": "string"
},
"status": {
"description": "Lifecycle status of the product",
"type": "string",
"enum": [
"DRAFT",
"ACTIVE",
"ARCHIVED"
]
}
},
"minProperties": 1
}
},
"required": [
"eventId",
"occurredAt",
"productId",
"changes"
]
}Rating Updated
EVTv1.0.0Broker:KafkaPublished when a product's aggregate rating changes as a result of a newly published review.
productIdstringRequiredaverageRatingnumberRequired0Maximum 5reviewCountintegerRequired0updatedAtstring date-timeRequiredOverview
RatingUpdated is published by the Rating Aggregator whenever a product's aggregate rating changes. Other domains (such as the storefront and search) can consume it to keep displayed ratings fresh.
Nothing in the catalog.
{
"productId": "string",
"averageRating": 0,
"reviewCount": 0,
"updatedAt": "2026-01-01T12:00:00Z"
}/** Published when a product's aggregate rating changes as a result of a newly published review. */
export interface RatingUpdated {
productId: string;
averageRating: number;
reviewCount: number;
updatedAt: string;
}{
"$schema": "http://json-schema.org/draft-07/schema#",
"title": "RatingUpdated",
"type": "object",
"properties": {
"productId": {
"type": "string"
},
"averageRating": {
"type": "number",
"minimum": 0,
"maximum": 5
},
"reviewCount": {
"type": "integer",
"minimum": 0
},
"updatedAt": {
"type": "string",
"format": "date-time"
}
},
"required": [
"productId",
"averageRating",
"reviewCount",
"updatedAt"
]
}Refund Processed
EVTv1.0.0Broker:KafkaPublished by Stripe when a refund has been processed.
Published when a refund has been processed
refundIdstring uuidRequiredpaymentIdstring uuidRequiredamountintegerRequiredAmount refunded, in minor units (e.g. cents)
currencystringRequired^[A-Z]{3}$processedAtstring date-timeRequiredOverview
RefundProcessed is delivered by Stripe's Webhook Endpoint when a requested refund has been processed. The Payment Worker consumes it and records the refund as complete.
{
"refundId": "3f6b2b8e-9a4c-4f0e-8f2a-1c2d3e4f5a6b",
"paymentId": "3f6b2b8e-9a4c-4f0e-8f2a-1c2d3e4f5a6b",
"amount": 0,
"currency": "string",
"processedAt": "2026-01-01T12:00:00Z"
}/** Published when a refund has been processed */
export interface RefundProcessed {
refundId: string;
paymentId: string;
/** Amount refunded, in minor units (e.g. cents) */
amount: number;
currency: string;
processedAt: string;
}{
"$schema": "http://json-schema.org/draft-07/schema#",
"title": "RefundProcessed",
"description": "Published when a refund has been processed",
"type": "object",
"properties": {
"refundId": {
"type": "string",
"format": "uuid"
},
"paymentId": {
"type": "string",
"format": "uuid"
},
"amount": {
"type": "integer",
"description": "Amount refunded, in minor units (e.g. cents)"
},
"currency": {
"type": "string",
"pattern": "^[A-Z]{3}$"
},
"processedAt": {
"type": "string",
"format": "date-time"
}
},
"required": [
"refundId",
"paymentId",
"amount",
"currency",
"processedAt"
]
}Refund Requested
EVTv1.0.0Broker:KafkaPublished when the Payment Processing System requests a refund from the payment processor.
Published when a refund is requested from the payment processor
refundIdstring uuidRequiredpaymentIdstring uuidRequiredorderIdstring uuidamountintegerRequiredAmount to refund, in minor units (e.g. cents)
0currencystringRequired^[A-Z]{3}$reasonstringrequestedAtstring date-timeRequiredOverview
RefundRequested is published by the Payment Worker to ask the external Stripe to refund a previous charge — for example when an order is cancelled after payment. Stripe responds with Refund Processed.
{
"refundId": "3f6b2b8e-9a4c-4f0e-8f2a-1c2d3e4f5a6b",
"paymentId": "3f6b2b8e-9a4c-4f0e-8f2a-1c2d3e4f5a6b",
"orderId": "3f6b2b8e-9a4c-4f0e-8f2a-1c2d3e4f5a6b",
"amount": 0,
"currency": "string",
"reason": "string",
"requestedAt": "2026-01-01T12:00:00Z"
}/** Published when a refund is requested from the payment processor */
export interface RefundRequested {
refundId: string;
paymentId: string;
orderId?: string;
/** Amount to refund, in minor units (e.g. cents) */
amount: number;
currency: string;
reason?: string;
requestedAt: string;
}{
"$schema": "http://json-schema.org/draft-07/schema#",
"title": "RefundRequested",
"description": "Published when a refund is requested from the payment processor",
"type": "object",
"properties": {
"refundId": {
"type": "string",
"format": "uuid"
},
"paymentId": {
"type": "string",
"format": "uuid"
},
"orderId": {
"type": "string",
"format": "uuid"
},
"amount": {
"type": "integer",
"minimum": 0,
"description": "Amount to refund, in minor units (e.g. cents)"
},
"currency": {
"type": "string",
"pattern": "^[A-Z]{3}$"
},
"reason": {
"type": "string"
},
"requestedAt": {
"type": "string",
"format": "date-time"
}
},
"required": [
"refundId",
"paymentId",
"amount",
"currency",
"requestedAt"
]
}Return Approved
EVTv1.0.0Broker:KafkaPublished when a return request passes the returns policy and the customer can send the items back.
Published when a return request has been approved
returnIdstring uuidRequiredorderIdstring uuidRequiredcustomerIdstring uuidRequiredreturnLabelUrlstring urireturnBystring dateapprovedAtstring date-timeRequiredOverview
ReturnApproved is published by the Returns Processor once a Return Requested passes policy checks. The Notification Service uses it to send the customer a return label and drop-off instructions.
{
"returnId": "3f6b2b8e-9a4c-4f0e-8f2a-1c2d3e4f5a6b",
"orderId": "3f6b2b8e-9a4c-4f0e-8f2a-1c2d3e4f5a6b",
"customerId": "3f6b2b8e-9a4c-4f0e-8f2a-1c2d3e4f5a6b",
"returnLabelUrl": "https://example.com",
"returnBy": "2026-01-01",
"approvedAt": "2026-01-01T12:00:00Z"
}/** Published when a return request has been approved */
export interface ReturnApproved {
returnId: string;
orderId: string;
customerId: string;
returnLabelUrl?: string;
returnBy?: string;
approvedAt: string;
}{
"$schema": "http://json-schema.org/draft-07/schema#",
"title": "ReturnApproved",
"description": "Published when a return request has been approved",
"type": "object",
"properties": {
"returnId": {
"type": "string",
"format": "uuid"
},
"orderId": {
"type": "string",
"format": "uuid"
},
"customerId": {
"type": "string",
"format": "uuid"
},
"returnLabelUrl": {
"type": "string",
"format": "uri"
},
"returnBy": {
"type": "string",
"format": "date"
},
"approvedAt": {
"type": "string",
"format": "date-time"
}
},
"required": [
"returnId",
"orderId",
"customerId",
"approvedAt"
]
}Return Received
EVTv1.0.0Broker:KafkaPublished when returned items have arrived at the warehouse and been inspected.
Published when returned items have arrived at the warehouse
returnIdstring uuidRequiredorderIdstring uuidRequireditemsarray of objectRequiredskustringRequiredquantityintegerRequired1conditionstringRequiredresellabledamagedrefundAmountnumberRequired0currencystringRequired3Max length 3receivedAtstring date-timeRequiredOverview
ReturnReceived is published by the Returns Processor when a returned parcel is scanned in at the warehouse. The Payment Worker refunds the customer and the Inventory Service restocks resellable items.
{
"returnId": "3f6b2b8e-9a4c-4f0e-8f2a-1c2d3e4f5a6b",
"orderId": "3f6b2b8e-9a4c-4f0e-8f2a-1c2d3e4f5a6b",
"items": [
{
"sku": "string",
"quantity": 1,
"condition": "resellable"
}
],
"refundAmount": 0,
"currency": "string",
"receivedAt": "2026-01-01T12:00:00Z"
}/** Published when returned items have arrived at the warehouse */
export interface ReturnReceived {
returnId: string;
orderId: string;
items: ({
sku: string;
quantity: number;
condition: "resellable" | "damaged";
})[];
refundAmount: number;
currency: string;
receivedAt: string;
}{
"$schema": "http://json-schema.org/draft-07/schema#",
"title": "ReturnReceived",
"description": "Published when returned items have arrived at the warehouse",
"type": "object",
"properties": {
"returnId": {
"type": "string",
"format": "uuid"
},
"orderId": {
"type": "string",
"format": "uuid"
},
"items": {
"type": "array",
"items": {
"type": "object",
"properties": {
"sku": {
"type": "string"
},
"quantity": {
"type": "integer",
"minimum": 1
},
"condition": {
"type": "string",
"enum": [
"resellable",
"damaged"
]
}
},
"required": [
"sku",
"quantity",
"condition"
]
}
},
"refundAmount": {
"type": "number",
"minimum": 0
},
"currency": {
"type": "string",
"minLength": 3,
"maxLength": 3
},
"receivedAt": {
"type": "string",
"format": "date-time"
}
},
"required": [
"returnId",
"orderId",
"items",
"refundAmount",
"currency",
"receivedAt"
]
}Return Requested
EVTv1.0.0Broker:KafkaPublished when a customer has requested to return items from an order.
Published when a customer has requested a return
returnIdstring uuidRequiredorderIdstring uuidRequiredcustomerIdstring uuidRequireditemsarray of objectRequiredskustringRequiredquantityintegerRequired1reasonstringrequestedAtstring date-timeRequiredOverview
ReturnRequested is published by the Returns API after it accepts a Request Return. The Returns Processor consumes it to apply the returns policy.
{
"returnId": "3f6b2b8e-9a4c-4f0e-8f2a-1c2d3e4f5a6b",
"orderId": "3f6b2b8e-9a4c-4f0e-8f2a-1c2d3e4f5a6b",
"customerId": "3f6b2b8e-9a4c-4f0e-8f2a-1c2d3e4f5a6b",
"items": [
{
"sku": "string",
"quantity": 1
}
],
"reason": "string",
"requestedAt": "2026-01-01T12:00:00Z"
}/** Published when a customer has requested a return */
export interface ReturnRequested {
returnId: string;
orderId: string;
customerId: string;
items: {
sku: string;
quantity: number;
}[];
reason?: string;
requestedAt: string;
}{
"$schema": "http://json-schema.org/draft-07/schema#",
"title": "ReturnRequested",
"description": "Published when a customer has requested a return",
"type": "object",
"properties": {
"returnId": {
"type": "string",
"format": "uuid"
},
"orderId": {
"type": "string",
"format": "uuid"
},
"customerId": {
"type": "string",
"format": "uuid"
},
"items": {
"type": "array",
"items": {
"type": "object",
"properties": {
"sku": {
"type": "string"
},
"quantity": {
"type": "integer",
"minimum": 1
}
},
"required": [
"sku",
"quantity"
]
}
},
"reason": {
"type": "string"
},
"requestedAt": {
"type": "string",
"format": "date-time"
}
},
"required": [
"returnId",
"orderId",
"customerId",
"items",
"requestedAt"
]
}Review Flagged
EVTv1.0.0Broker:KafkaPublished when a published review is flagged and needs to be screened again.
reviewIdstring uuidRequiredproductIdstringRequiredreasonstringRequiredspamabuseoff_topicinappropriateotherflagCountintegerTotal flags this review has now received.
1flaggedAtstring date-timeRequiredOverview
ReviewFlagged is published by the Review API when a published review is flagged. The Review Moderation Worker consumes it and re-screens the review, which may lead to it being rejected.
{
"reviewId": "3f6b2b8e-9a4c-4f0e-8f2a-1c2d3e4f5a6b",
"productId": "string",
"reason": "spam",
"flagCount": 1,
"flaggedAt": "2026-01-01T12:00:00Z"
}/** Published when a published review is flagged and needs to be screened again. */
export interface ReviewFlagged {
reviewId: string;
productId: string;
reason: "spam" | "abuse" | "off_topic" | "inappropriate" | "other";
/** Total flags this review has now received. */
flagCount?: number;
flaggedAt: string;
}{
"$schema": "http://json-schema.org/draft-07/schema#",
"title": "ReviewFlagged",
"type": "object",
"properties": {
"reviewId": {
"type": "string",
"format": "uuid"
},
"productId": {
"type": "string"
},
"reason": {
"type": "string",
"enum": [
"spam",
"abuse",
"off_topic",
"inappropriate",
"other"
]
},
"flagCount": {
"type": "integer",
"minimum": 1,
"description": "Total flags this review has now received."
},
"flaggedAt": {
"type": "string",
"format": "date-time"
}
},
"required": [
"reviewId",
"productId",
"reason",
"flaggedAt"
]
}Review Helpful Voted
EVTv1.0.0Broker:KafkaPublished when a review's helpful count changes as a result of a customer vote.
reviewIdstring uuidRequiredproductIdstringRequiredhelpfulCountintegerRequired0updatedAtstring date-timeRequiredOverview
ReviewHelpfulVoted is published by the Review API whenever a review's helpful count changes. It lets other surfaces (such as the storefront) keep "most helpful" ordering fresh.
Nothing in the catalog.
{
"reviewId": "3f6b2b8e-9a4c-4f0e-8f2a-1c2d3e4f5a6b",
"productId": "string",
"helpfulCount": 0,
"updatedAt": "2026-01-01T12:00:00Z"
}/** Published when a review's helpful count changes as a result of a customer vote. */
export interface ReviewHelpfulVoted {
reviewId: string;
productId: string;
helpfulCount: number;
updatedAt: string;
}{
"$schema": "http://json-schema.org/draft-07/schema#",
"title": "ReviewHelpfulVoted",
"type": "object",
"properties": {
"reviewId": {
"type": "string",
"format": "uuid"
},
"productId": {
"type": "string"
},
"helpfulCount": {
"type": "integer",
"minimum": 0
},
"updatedAt": {
"type": "string",
"format": "date-time"
}
},
"required": [
"reviewId",
"productId",
"helpfulCount",
"updatedAt"
]
}Review Published
EVTv1.0.0Broker:KafkaPublished when a submitted review passes moderation and becomes visible on the storefront.
reviewIdstring uuidRequiredproductIdstringRequiredcustomerIdstringratingintegerRequired1Maximum 5publishedAtstring date-timeRequiredOverview
ReviewPublished is published by the Review Moderation Worker when a review passes moderation. The Rating Aggregator consumes it to update the product's aggregate rating.
{
"reviewId": "3f6b2b8e-9a4c-4f0e-8f2a-1c2d3e4f5a6b",
"productId": "string",
"customerId": "string",
"rating": 1,
"publishedAt": "2026-01-01T12:00:00Z"
}/** Published when a submitted review passes moderation and becomes visible on the storefront. */
export interface ReviewPublished {
reviewId: string;
productId: string;
customerId?: string;
rating: number;
publishedAt: string;
}{
"$schema": "http://json-schema.org/draft-07/schema#",
"title": "ReviewPublished",
"type": "object",
"properties": {
"reviewId": {
"type": "string",
"format": "uuid"
},
"productId": {
"type": "string"
},
"customerId": {
"type": "string"
},
"rating": {
"type": "integer",
"minimum": 1,
"maximum": 5
},
"publishedAt": {
"type": "string",
"format": "date-time"
}
},
"required": [
"reviewId",
"productId",
"rating",
"publishedAt"
]
}Review Rejected
EVTv1.0.0Broker:KafkaPublished when a submitted review fails moderation (spam, abuse or policy violation) and will not be shown.
reviewIdstring uuidRequiredproductIdstringRequiredreasonstringRequiredspamabuseoff_topicpolicy_violationrejectedAtstring date-timeRequiredOverview
ReviewRejected is published by the Review Moderation Worker when a review fails moderation. The review is kept for audit but never published to the storefront.
Nothing in the catalog.
{
"reviewId": "3f6b2b8e-9a4c-4f0e-8f2a-1c2d3e4f5a6b",
"productId": "string",
"reason": "spam",
"rejectedAt": "2026-01-01T12:00:00Z"
}/** Published when a submitted review fails moderation (spam, abuse or policy violation) and will not be shown. */
export interface ReviewRejected {
reviewId: string;
productId: string;
reason: "spam" | "abuse" | "off_topic" | "policy_violation";
rejectedAt: string;
}{
"$schema": "http://json-schema.org/draft-07/schema#",
"title": "ReviewRejected",
"type": "object",
"properties": {
"reviewId": {
"type": "string",
"format": "uuid"
},
"productId": {
"type": "string"
},
"reason": {
"type": "string",
"enum": [
"spam",
"abuse",
"off_topic",
"policy_violation"
]
},
"rejectedAt": {
"type": "string",
"format": "date-time"
}
},
"required": [
"reviewId",
"productId",
"reason",
"rejectedAt"
]
}Review Submitted
EVTv1.0.0Broker:KafkaPublished when a customer submits a review. The review is stored but not yet visible — it awaits moderation.
reviewIdstring uuidRequiredproductIdstringRequiredcustomerIdstringRequiredratingintegerRequired1Maximum 5titlestringbodystringsubmittedAtstring date-timeRequiredOverview
ReviewSubmitted is published by the Review API once a review has been accepted and stored. The Review Moderation Worker consumes it to screen the review before it can be published.
{
"reviewId": "3f6b2b8e-9a4c-4f0e-8f2a-1c2d3e4f5a6b",
"productId": "string",
"customerId": "string",
"rating": 1,
"title": "string",
"body": "string",
"submittedAt": "2026-01-01T12:00:00Z"
}/** Published when a customer submits a review. The review is stored but not yet visible — it awaits moderation. */
export interface ReviewSubmitted {
reviewId: string;
productId: string;
customerId: string;
rating: number;
title?: string;
body?: string;
submittedAt: string;
}{
"$schema": "http://json-schema.org/draft-07/schema#",
"title": "ReviewSubmitted",
"type": "object",
"properties": {
"reviewId": {
"type": "string",
"format": "uuid"
},
"productId": {
"type": "string"
},
"customerId": {
"type": "string"
},
"rating": {
"type": "integer",
"minimum": 1,
"maximum": 5
},
"title": {
"type": "string"
},
"body": {
"type": "string"
},
"submittedAt": {
"type": "string",
"format": "date-time"
}
},
"required": [
"reviewId",
"productId",
"customerId",
"rating",
"submittedAt"
]
}Shipment Created
EVTv1.0.0Broker:KafkaPublished by the carrier when a shipment has been created and dispatched.
Published when a shipment has been created and dispatched
shipmentIdstring uuidRequiredorderIdstring uuidRequiredtrackingNumberstringRequiredcarrierstringestimatedDeliverystring datecreatedAtstring date-timeRequiredOverview
ShipmentCreated is published by the carrier's Tracking API when a shipment has been created and dispatched. Acme Inc consumes it to give the customer a tracking number and expected delivery date.
Nothing in the catalog.
{
"shipmentId": "3f6b2b8e-9a4c-4f0e-8f2a-1c2d3e4f5a6b",
"orderId": "3f6b2b8e-9a4c-4f0e-8f2a-1c2d3e4f5a6b",
"trackingNumber": "string",
"carrier": "string",
"estimatedDelivery": "2026-01-01",
"createdAt": "2026-01-01T12:00:00Z"
}/** Published when a shipment has been created and dispatched */
export interface ShipmentCreated {
shipmentId: string;
orderId: string;
trackingNumber: string;
carrier?: string;
estimatedDelivery?: string;
createdAt: string;
}{
"$schema": "http://json-schema.org/draft-07/schema#",
"title": "ShipmentCreated",
"description": "Published when a shipment has been created and dispatched",
"type": "object",
"properties": {
"shipmentId": {
"type": "string",
"format": "uuid"
},
"orderId": {
"type": "string",
"format": "uuid"
},
"trackingNumber": {
"type": "string"
},
"carrier": {
"type": "string"
},
"estimatedDelivery": {
"type": "string",
"format": "date"
},
"createdAt": {
"type": "string",
"format": "date-time"
}
},
"required": [
"shipmentId",
"orderId",
"trackingNumber",
"createdAt"
]
}Shipment Delivered
EVTv1.0.0Broker:KafkaPublished by the carrier when a shipment has been delivered to the customer.
Published when a shipment has been delivered to the customer
shipmentIdstring uuidRequiredorderIdstring uuidRequireddeliveredAtstring date-timeRequiredsignedBystringName of the person who accepted delivery, if captured
Overview
ShipmentDelivered is published by the carrier's Tracking API when a shipment reaches the customer. This is the happy-path end of the fulfilment journey — Acme Inc consumes it to close out the order and prompt the customer for feedback.
{
"shipmentId": "3f6b2b8e-9a4c-4f0e-8f2a-1c2d3e4f5a6b",
"orderId": "3f6b2b8e-9a4c-4f0e-8f2a-1c2d3e4f5a6b",
"deliveredAt": "2026-01-01T12:00:00Z",
"signedBy": "string"
}/** Published when a shipment has been delivered to the customer */
export interface ShipmentDelivered {
shipmentId: string;
orderId: string;
deliveredAt: string;
/** Name of the person who accepted delivery, if captured */
signedBy?: string;
}{
"$schema": "http://json-schema.org/draft-07/schema#",
"title": "ShipmentDelivered",
"description": "Published when a shipment has been delivered to the customer",
"type": "object",
"properties": {
"shipmentId": {
"type": "string",
"format": "uuid"
},
"orderId": {
"type": "string",
"format": "uuid"
},
"deliveredAt": {
"type": "string",
"format": "date-time"
},
"signedBy": {
"type": "string",
"description": "Name of the person who accepted delivery, if captured"
}
},
"required": [
"shipmentId",
"orderId",
"deliveredAt"
]
}Shipment Failed
EVTv1.0.0Broker:KafkaPublished by the carrier when a shipment could not be delivered.
Published when a shipment could not be delivered
shipmentIdstring uuidRequiredorderIdstring uuidRequiredreasonstringRequiredFAILED_DELIVERYLOSTDAMAGEDRETURNED_TO_SENDERfailedAtstring date-timeRequiredOverview
ShipmentFailed is published by the carrier's Tracking API when a shipment cannot be delivered — for example a failed delivery attempt or a lost parcel. Acme Inc consumes it to trigger a redelivery, refund, or customer follow-up.
Nothing in the catalog.
{
"shipmentId": "3f6b2b8e-9a4c-4f0e-8f2a-1c2d3e4f5a6b",
"orderId": "3f6b2b8e-9a4c-4f0e-8f2a-1c2d3e4f5a6b",
"reason": "FAILED_DELIVERY",
"failedAt": "2026-01-01T12:00:00Z"
}/** Published when a shipment could not be delivered */
export interface ShipmentFailed {
shipmentId: string;
orderId: string;
reason: "FAILED_DELIVERY" | "LOST" | "DAMAGED" | "RETURNED_TO_SENDER";
failedAt: string;
}{
"$schema": "http://json-schema.org/draft-07/schema#",
"title": "ShipmentFailed",
"description": "Published when a shipment could not be delivered",
"type": "object",
"properties": {
"shipmentId": {
"type": "string",
"format": "uuid"
},
"orderId": {
"type": "string",
"format": "uuid"
},
"reason": {
"type": "string",
"enum": [
"FAILED_DELIVERY",
"LOST",
"DAMAGED",
"RETURNED_TO_SENDER"
]
},
"failedAt": {
"type": "string",
"format": "date-time"
}
},
"required": [
"shipmentId",
"orderId",
"reason",
"failedAt"
]
}Commands
Requests for one service to do something. They can be rejected.
Add Item To Cart
POST /carts/{cartId}/itemsv1.0.0Command to add an item to a shopping cart.
Command to add an item to a shopping cart
cartIdstring uuidRequiredUnique identifier of the cart
productIdstring uuidRequiredIdentifier of the product to add
quantityintegerRequiredNumber of units to add Defaults to 1.
1Overview
AddItemToCart is handled by the Cart API. It adds an item (or increases its quantity) in the cart and persists the change to the Cart Database.
Nothing in the catalog.
{
"cartId": "3f6b2b8e-9a4c-4f0e-8f2a-1c2d3e4f5a6b",
"productId": "3f6b2b8e-9a4c-4f0e-8f2a-1c2d3e4f5a6b",
"quantity": 1
}/** Command to add an item to a shopping cart */
export interface AddItemToCart {
/** Unique identifier of the cart */
cartId: string;
/** Identifier of the product to add */
productId: string;
/** Number of units to add */
quantity: number;
}{
"$schema": "http://json-schema.org/draft-07/schema#",
"title": "AddItemToCart",
"description": "Command to add an item to a shopping cart",
"type": "object",
"properties": {
"cartId": {
"description": "Unique identifier of the cart",
"type": "string",
"format": "uuid"
},
"productId": {
"description": "Identifier of the product to add",
"type": "string",
"format": "uuid"
},
"quantity": {
"description": "Number of units to add",
"type": "integer",
"minimum": 1,
"default": 1
}
},
"required": [
"cartId",
"productId",
"quantity"
]
}Authenticate Customer
POST /oauth/tokenv1.0.0Command to authenticate a customer with their credentials.
Command to authenticate a customer with their credentials, and the token returned
requestobjectRequiredThe credentials to authenticate
emailstring emailRequiredpasswordstringRequiredresponseobjectRequiredThe access token issued on a successful sign-in
accessTokenstringRequiredtokenTypestringRequiredBearerexpiresInintegerRequiredToken lifetime in seconds
Overview
AuthenticateCustomer is handled by the OAuth API. It verifies the supplied credentials against the User Directory and, on success, returns an access token and publishes a Customer Authenticated event.
Nothing in the catalog.
{
"request": {
"email": "jane@example.com",
"password": "string"
},
"response": {
"accessToken": "string",
"tokenType": "Bearer",
"expiresIn": 0
}
}/** Command to authenticate a customer with their credentials, and the token returned */
export interface AuthenticateCustomer {
/** The credentials to authenticate */
request: {
email: string;
password: string;
};
/** The access token issued on a successful sign-in */
response: {
accessToken: string;
tokenType: "Bearer";
/** Token lifetime in seconds */
expiresIn: number;
};
}{
"$schema": "http://json-schema.org/draft-07/schema#",
"title": "AuthenticateCustomer",
"description": "Command to authenticate a customer with their credentials, and the token returned",
"type": "object",
"properties": {
"request": {
"description": "The credentials to authenticate",
"type": "object",
"properties": {
"email": {
"type": "string",
"format": "email"
},
"password": {
"type": "string"
}
},
"required": [
"email",
"password"
]
},
"response": {
"description": "The access token issued on a successful sign-in",
"type": "object",
"properties": {
"accessToken": {
"type": "string"
},
"tokenType": {
"type": "string",
"enum": [
"Bearer"
]
},
"expiresIn": {
"description": "Token lifetime in seconds",
"type": "integer"
}
},
"required": [
"accessToken",
"tokenType",
"expiresIn"
]
}
},
"required": [
"request",
"response"
]
}Authorize Payment
POST /payments/authorizev1.0.0Command to authorize payment for the total of a checked-out cart.
Command to authorize payment for the total of a checked-out cart
cartIdstring uuidRequiredIdentifier of the cart being checked out
customerIdstring uuidIdentifier of the customer paying
amountintegerRequiredAmount to authorize, in minor units (e.g. cents)
0currencystringRequiredISO 4217 currency code
^[A-Z]{3}$Overview
AuthorizePayment is sent by the Checkout Orchestrator to authorize payment for the order total. Authorization places a hold on the customer's payment method; the funds are captured once the order is created. If a later step fails, the authorization is voided.
{
"cartId": "3f6b2b8e-9a4c-4f0e-8f2a-1c2d3e4f5a6b",
"customerId": "3f6b2b8e-9a4c-4f0e-8f2a-1c2d3e4f5a6b",
"amount": 0,
"currency": "string"
}/** Command to authorize payment for the total of a checked-out cart */
export interface AuthorizePayment {
/** Identifier of the cart being checked out */
cartId: string;
/** Identifier of the customer paying */
customerId?: string;
/** Amount to authorize, in minor units (e.g. cents) */
amount: number;
/** ISO 4217 currency code */
currency: string;
}{
"$schema": "http://json-schema.org/draft-07/schema#",
"title": "AuthorizePayment",
"description": "Command to authorize payment for the total of a checked-out cart",
"type": "object",
"properties": {
"cartId": {
"description": "Identifier of the cart being checked out",
"type": "string",
"format": "uuid"
},
"customerId": {
"description": "Identifier of the customer paying",
"type": "string",
"format": "uuid"
},
"amount": {
"description": "Amount to authorize, in minor units (e.g. cents)",
"type": "integer",
"minimum": 0
},
"currency": {
"description": "ISO 4217 currency code",
"type": "string",
"pattern": "^[A-Z]{3}$"
}
},
"required": [
"cartId",
"amount",
"currency"
]
}Calculate Discount
POST /discounts/calculatev1.0.0Command to calculate the discount that applies to a cart.
Command to calculate the discount for a cart, and the discount returned
requestobjectRequiredcartIdstring uuidRequiredcustomerIdstring uuidsubtotalintegerRequiredCart subtotal before discounts, in minor units (e.g. cents)
0currencystringRequired^[A-Z]{3}$promotionCodestringOptional promotion code supplied by the customer
responseobjectRequireddiscountintegerRequiredTotal discount to apply, in minor units (e.g. cents)
0appliedPromotionsarray of stringOverview
CalculateDiscount is handled by the Promotion Service. It is sent by the Cart API when pricing a cart. The service evaluates the applicable promotion rules and returns the discount, also publishing a Discount Calculated event.
{
"request": {
"cartId": "3f6b2b8e-9a4c-4f0e-8f2a-1c2d3e4f5a6b",
"customerId": "3f6b2b8e-9a4c-4f0e-8f2a-1c2d3e4f5a6b",
"subtotal": 0,
"currency": "string",
"promotionCode": "string"
},
"response": {
"discount": 0,
"appliedPromotions": [
"string"
]
}
}/** Command to calculate the discount for a cart, and the discount returned */
export interface CalculateDiscount {
request: {
cartId: string;
customerId?: string;
/** Cart subtotal before discounts, in minor units (e.g. cents) */
subtotal: number;
currency: string;
/** Optional promotion code supplied by the customer */
promotionCode?: string;
};
response: {
/** Total discount to apply, in minor units (e.g. cents) */
discount: number;
appliedPromotions?: string[];
};
}{
"$schema": "http://json-schema.org/draft-07/schema#",
"title": "CalculateDiscount",
"description": "Command to calculate the discount for a cart, and the discount returned",
"type": "object",
"properties": {
"request": {
"type": "object",
"properties": {
"cartId": {
"type": "string",
"format": "uuid"
},
"customerId": {
"type": "string",
"format": "uuid"
},
"subtotal": {
"description": "Cart subtotal before discounts, in minor units (e.g. cents)",
"type": "integer",
"minimum": 0
},
"currency": {
"type": "string",
"pattern": "^[A-Z]{3}$"
},
"promotionCode": {
"description": "Optional promotion code supplied by the customer",
"type": "string"
}
},
"required": [
"cartId",
"subtotal",
"currency"
]
},
"response": {
"type": "object",
"properties": {
"discount": {
"description": "Total discount to apply, in minor units (e.g. cents)",
"type": "integer",
"minimum": 0
},
"appliedPromotions": {
"type": "array",
"items": {
"type": "string"
}
}
},
"required": [
"discount"
]
}
},
"required": [
"request",
"response"
]
}Cancel Order
POST /orders/{orderId}/cancelv1.0.0Command to cancel an existing order.
Command to cancel an existing order
orderIdstring uuidRequiredIdentifier of the order to cancel
reasonstringRequiredWhy the order is being cancelled
CUSTOMER_REQUESTEDPAYMENT_FAILEDOUT_OF_STOCKFRAUDOverview
CancelOrder is handled by the Order Service. It cancels an order that has not yet been completed — releasing any reservations and voiding the payment authorization where needed. On success the Order Service publishes an Order Cancelled event.
Nothing in the catalog.
{
"orderId": "3f6b2b8e-9a4c-4f0e-8f2a-1c2d3e4f5a6b",
"reason": "CUSTOMER_REQUESTED"
}/** Command to cancel an existing order */
export interface CancelOrder {
/** Identifier of the order to cancel */
orderId: string;
/** Why the order is being cancelled */
reason: "CUSTOMER_REQUESTED" | "PAYMENT_FAILED" | "OUT_OF_STOCK" | "FRAUD";
}{
"$schema": "http://json-schema.org/draft-07/schema#",
"title": "CancelOrder",
"description": "Command to cancel an existing order",
"type": "object",
"properties": {
"orderId": {
"description": "Identifier of the order to cancel",
"type": "string",
"format": "uuid"
},
"reason": {
"description": "Why the order is being cancelled",
"type": "string",
"enum": [
"CUSTOMER_REQUESTED",
"PAYMENT_FAILED",
"OUT_OF_STOCK",
"FRAUD"
]
}
},
"required": [
"orderId",
"reason"
]
}Checkout Cart
POST /carts/{cartId}/checkoutv1.0.0Command to check out a shopping cart.
Command to check out a shopping cart
cartIdstring uuidRequiredUnique identifier of the cart to check out
customerIdstring uuidRequiredIdentifier of the customer checking out
promotionCodestringOptional promotion code to apply at checkout
Overview
CheckoutCart is handled by the Cart API. It finalises the cart — pricing it (including discounts from the Promotion System) — and on success publishes a Cart Checked Out event.
Nothing in the catalog.
{
"cartId": "3f6b2b8e-9a4c-4f0e-8f2a-1c2d3e4f5a6b",
"customerId": "3f6b2b8e-9a4c-4f0e-8f2a-1c2d3e4f5a6b",
"promotionCode": "string"
}/** Command to check out a shopping cart */
export interface CheckoutCart {
/** Unique identifier of the cart to check out */
cartId: string;
/** Identifier of the customer checking out */
customerId: string;
/** Optional promotion code to apply at checkout */
promotionCode?: string;
}{
"$schema": "http://json-schema.org/draft-07/schema#",
"title": "CheckoutCart",
"description": "Command to check out a shopping cart",
"type": "object",
"properties": {
"cartId": {
"description": "Unique identifier of the cart to check out",
"type": "string",
"format": "uuid"
},
"customerId": {
"description": "Identifier of the customer checking out",
"type": "string",
"format": "uuid"
},
"promotionCode": {
"description": "Optional promotion code to apply at checkout",
"type": "string"
}
},
"required": [
"cartId",
"customerId"
]
}Create Order
POST /ordersv1.0.0Command to create a new order from a checked-out cart.
Command to create a new order from a checked-out cart
cartIdstring uuidRequiredIdentifier of the cart this order was created from
customerIdstring uuidRequiredIdentifier of the customer placing the order
itemsarray of objectRequiredThe items in the order
productIdstring uuidRequiredquantityintegerRequired1unitPriceintegerRequiredPrice per unit in minor units (e.g. cents)
totalintegerRequiredOrder total in minor units (e.g. cents)
0currencystringRequiredISO 4217 currency code
^[A-Z]{3}$paymentAuthorizationIdstringIdentifier of the payment authorization for this order
Overview
CreateOrder is sent by the Checkout Orchestrator and handled by the Order Service. It is the final step of the checkout saga — once inventory is reserved and payment is authorized, this command creates the order. On success the Order Service publishes an Order Created event.
{
"cartId": "3f6b2b8e-9a4c-4f0e-8f2a-1c2d3e4f5a6b",
"customerId": "3f6b2b8e-9a4c-4f0e-8f2a-1c2d3e4f5a6b",
"items": [
{
"productId": "3f6b2b8e-9a4c-4f0e-8f2a-1c2d3e4f5a6b",
"quantity": 1,
"unitPrice": 0
}
],
"total": 0,
"currency": "string",
"paymentAuthorizationId": "string"
}/** Command to create a new order from a checked-out cart */
export interface CreateOrder {
/** Identifier of the cart this order was created from */
cartId: string;
/** Identifier of the customer placing the order */
customerId: string;
/** The items in the order */
items: {
productId: string;
quantity: number;
/** Price per unit in minor units (e.g. cents) */
unitPrice: number;
}[];
/** Order total in minor units (e.g. cents) */
total: number;
/** ISO 4217 currency code */
currency: string;
/** Identifier of the payment authorization for this order */
paymentAuthorizationId?: string;
}{
"$schema": "http://json-schema.org/draft-07/schema#",
"title": "CreateOrder",
"description": "Command to create a new order from a checked-out cart",
"type": "object",
"properties": {
"cartId": {
"description": "Identifier of the cart this order was created from",
"type": "string",
"format": "uuid"
},
"customerId": {
"description": "Identifier of the customer placing the order",
"type": "string",
"format": "uuid"
},
"items": {
"description": "The items in the order",
"type": "array",
"items": {
"type": "object",
"properties": {
"productId": {
"type": "string",
"format": "uuid"
},
"quantity": {
"type": "integer",
"minimum": 1
},
"unitPrice": {
"type": "integer",
"description": "Price per unit in minor units (e.g. cents)"
}
},
"required": [
"productId",
"quantity",
"unitPrice"
]
}
},
"total": {
"description": "Order total in minor units (e.g. cents)",
"type": "integer",
"minimum": 0
},
"currency": {
"description": "ISO 4217 currency code",
"type": "string",
"pattern": "^[A-Z]{3}$"
},
"paymentAuthorizationId": {
"description": "Identifier of the payment authorization for this order",
"type": "string"
}
},
"required": [
"cartId",
"customerId",
"items",
"total",
"currency"
]
}Create Product
POST /productsv1.0.0Command to add a new product to the catalog.
Command to add a new product to the catalog
skustringRequiredStock keeping unit — must be unique
namestringRequiredDisplay name of the product
1descriptionstringLong-form product description
priceintegerRequiredPrice in minor units (e.g. cents)
0currencystringRequiredISO 4217 currency code
^[A-Z]{3}$categorystringCategory the product belongs to
statusstringInitial lifecycle status — defaults to DRAFT
DRAFTACTIVEARCHIVEDOverview
CreateProduct is handled by the Product API. It validates the incoming product, writes it to the Product Database, and on success publishes a Product Created event.
Nothing in the catalog.
{
"sku": "string",
"name": "string",
"description": "string",
"price": 0,
"currency": "string",
"category": "string",
"status": "DRAFT"
}/** Command to add a new product to the catalog */
export interface CreateProduct {
/** Stock keeping unit — must be unique */
sku: string;
/** Display name of the product */
name: string;
/** Long-form product description */
description?: string;
/** Price in minor units (e.g. cents) */
price: number;
/** ISO 4217 currency code */
currency: string;
/** Category the product belongs to */
category?: string;
/** Initial lifecycle status — defaults to DRAFT */
status?: "DRAFT" | "ACTIVE" | "ARCHIVED";
}{
"$schema": "http://json-schema.org/draft-07/schema#",
"title": "CreateProduct",
"description": "Command to add a new product to the catalog",
"type": "object",
"properties": {
"sku": {
"description": "Stock keeping unit — must be unique",
"type": "string"
},
"name": {
"description": "Display name of the product",
"type": "string",
"minLength": 1
},
"description": {
"description": "Long-form product description",
"type": "string"
},
"price": {
"description": "Price in minor units (e.g. cents)",
"type": "integer",
"minimum": 0
},
"currency": {
"description": "ISO 4217 currency code",
"type": "string",
"pattern": "^[A-Z]{3}$"
},
"category": {
"description": "Category the product belongs to",
"type": "string"
},
"status": {
"description": "Initial lifecycle status — defaults to DRAFT",
"type": "string",
"enum": [
"DRAFT",
"ACTIVE",
"ARCHIVED"
]
}
},
"required": [
"sku",
"name",
"price",
"currency"
]
}Create Shipment
POST /shipmentsv1.0.0Command to create a shipment with a carrier for a packed order.
Command to create a shipment with a carrier for a packed order
orderIdstring uuidRequiredcarrierstringThe carrier to ship with
servicestringSTANDARDEXPRESSNEXT_DAYparcelCountinteger1destinationobjectRequiredline1stringRequiredcitystringRequiredpostcodestringRequiredcountrystringRequired^[A-Z]{2}$Overview
CreateShipment is sent by the Carrier Adapter to the external Carrier to dispatch a packed order. The carrier responds asynchronously with Shipment Created and later Shipment Delivered or Shipment Failed.
{
"orderId": "3f6b2b8e-9a4c-4f0e-8f2a-1c2d3e4f5a6b",
"carrier": "string",
"service": "STANDARD",
"parcelCount": 1,
"destination": {
"line1": "string",
"city": "string",
"postcode": "string",
"country": "string"
}
}/** Command to create a shipment with a carrier for a packed order */
export interface CreateShipment {
orderId: string;
/** The carrier to ship with */
carrier?: string;
service?: "STANDARD" | "EXPRESS" | "NEXT_DAY";
parcelCount?: number;
destination: {
line1: string;
city: string;
postcode: string;
country: string;
};
}{
"$schema": "http://json-schema.org/draft-07/schema#",
"title": "CreateShipment",
"description": "Command to create a shipment with a carrier for a packed order",
"type": "object",
"properties": {
"orderId": {
"type": "string",
"format": "uuid"
},
"carrier": {
"type": "string",
"description": "The carrier to ship with"
},
"service": {
"type": "string",
"enum": [
"STANDARD",
"EXPRESS",
"NEXT_DAY"
]
},
"parcelCount": {
"type": "integer",
"minimum": 1
},
"destination": {
"type": "object",
"properties": {
"line1": {
"type": "string"
},
"city": {
"type": "string"
},
"postcode": {
"type": "string"
},
"country": {
"type": "string",
"pattern": "^[A-Z]{2}$"
}
},
"required": [
"line1",
"city",
"postcode",
"country"
]
}
},
"required": [
"orderId",
"destination"
]
}Delete Product
DELETE /products/{productId}v1.0.0Command to remove a product from the catalog.
Command to remove a product from the catalog
productIdstring uuidRequiredUnique identifier of the product to delete
reasonstringOptional reason the product is being removed
DISCONTINUEDDUPLICATEMERCHANT_REQUESTOTHEROverview
DeleteProduct is handled by the Product API. It removes a product from the Product Database and, on success, publishes a Product Deleted event so downstream systems can clean up.
Nothing in the catalog.
{
"productId": "3f6b2b8e-9a4c-4f0e-8f2a-1c2d3e4f5a6b",
"reason": "DISCONTINUED"
}/** Command to remove a product from the catalog */
export interface DeleteProduct {
/** Unique identifier of the product to delete */
productId: string;
/** Optional reason the product is being removed */
reason?: "DISCONTINUED" | "DUPLICATE" | "MERCHANT_REQUEST" | "OTHER";
}{
"$schema": "http://json-schema.org/draft-07/schema#",
"title": "DeleteProduct",
"description": "Command to remove a product from the catalog",
"type": "object",
"properties": {
"productId": {
"description": "Unique identifier of the product to delete",
"type": "string",
"format": "uuid"
},
"reason": {
"description": "Optional reason the product is being removed",
"type": "string",
"enum": [
"DISCONTINUED",
"DUPLICATE",
"MERCHANT_REQUEST",
"OTHER"
]
}
},
"required": [
"productId"
]
}Flag Review
CMDv1.0.0Broker:KafkaCommand issued by a customer or moderator to flag a published review for re-moderation.
reviewIdstring uuidRequiredflaggedBystringRequiredCustomer or moderator id raising the flag.
reasonstringRequiredspamabuseoff_topicinappropriateothernotesstring1000flaggedAtstring date-timeRequiredOverview
FlagReview is sent to the Review API when someone reports a published review as inappropriate. The API records the flag and publishes Review Flagged so the review can be screened again.
Nothing in the catalog.
{
"reviewId": "3f6b2b8e-9a4c-4f0e-8f2a-1c2d3e4f5a6b",
"flaggedBy": "string",
"reason": "spam",
"notes": "string",
"flaggedAt": "2026-01-01T12:00:00Z"
}/** Command issued by a customer or moderator to flag a published review for re-moderation. */
export interface FlagReview {
reviewId: string;
/** Customer or moderator id raising the flag. */
flaggedBy: string;
reason: "spam" | "abuse" | "off_topic" | "inappropriate" | "other";
notes?: string;
flaggedAt: string;
}{
"$schema": "http://json-schema.org/draft-07/schema#",
"title": "FlagReview",
"type": "object",
"properties": {
"reviewId": {
"type": "string",
"format": "uuid"
},
"flaggedBy": {
"type": "string",
"description": "Customer or moderator id raising the flag."
},
"reason": {
"type": "string",
"enum": [
"spam",
"abuse",
"off_topic",
"inappropriate",
"other"
]
},
"notes": {
"type": "string",
"maxLength": 1000
},
"flaggedAt": {
"type": "string",
"format": "date-time"
}
},
"required": [
"reviewId",
"flaggedBy",
"reason",
"flaggedAt"
]
}Register Customer
POST /customersv1.0.0Command to register a new customer.
Command to register a new customer
emailstring emailRequiredCustomer's email address — must be unique
namestringCustomer's full name
1passwordstringRequiredInitial password for the customer's credentials
8Overview
RegisterCustomer is handled by the Customer API. It validates the new customer, writes it to the Customer Database, and on success publishes a Customer Registered event.
Nothing in the catalog.
{
"email": "jane@example.com",
"name": "string",
"password": "string"
}/** Command to register a new customer */
export interface RegisterCustomer {
/** Customer's email address — must be unique */
email: string;
/** Customer's full name */
name?: string;
/** Initial password for the customer's credentials */
password: string;
}{
"$schema": "http://json-schema.org/draft-07/schema#",
"title": "RegisterCustomer",
"description": "Command to register a new customer",
"type": "object",
"properties": {
"email": {
"description": "Customer's email address — must be unique",
"type": "string",
"format": "email"
},
"name": {
"description": "Customer's full name",
"type": "string",
"minLength": 1
},
"password": {
"description": "Initial password for the customer's credentials",
"type": "string",
"minLength": 8
}
},
"required": [
"email",
"password"
]
}Release Inventory
POST /reservations/{reservationId}/releasev1.0.0Command to release a previously held inventory reservation.
Command to release a previously held inventory reservation
reservationIdstring uuidRequiredreasonstringCHECKOUT_FAILEDORDER_CANCELLEDEXPIREDOverview
ReleaseInventory is handled by the Inventory Service. It releases a reservation that is no longer needed — for example when checkout fails after stock was reserved, or an order is cancelled.
Nothing in the catalog.
{
"reservationId": "3f6b2b8e-9a4c-4f0e-8f2a-1c2d3e4f5a6b",
"reason": "CHECKOUT_FAILED"
}/** Command to release a previously held inventory reservation */
export interface ReleaseInventory {
reservationId: string;
reason?: "CHECKOUT_FAILED" | "ORDER_CANCELLED" | "EXPIRED";
}{
"$schema": "http://json-schema.org/draft-07/schema#",
"title": "ReleaseInventory",
"description": "Command to release a previously held inventory reservation",
"type": "object",
"properties": {
"reservationId": {
"type": "string",
"format": "uuid"
},
"reason": {
"type": "string",
"enum": [
"CHECKOUT_FAILED",
"ORDER_CANCELLED",
"EXPIRED"
]
}
},
"required": [
"reservationId"
]
}Remove Item From Cart
DELETE /carts/{cartId}/items/{productId}v1.0.0Command to remove an item from a shopping cart.
Command to remove an item from a shopping cart
cartIdstring uuidRequiredUnique identifier of the cart
productIdstring uuidRequiredIdentifier of the product to remove
quantityintegerNumber of units to remove. If omitted, removes the item entirely.
1Overview
RemoveItemFromCart is handled by the Cart API. It removes an item from the cart (or decreases its quantity) and persists the change to the Cart Database.
Nothing in the catalog.
{
"cartId": "3f6b2b8e-9a4c-4f0e-8f2a-1c2d3e4f5a6b",
"productId": "3f6b2b8e-9a4c-4f0e-8f2a-1c2d3e4f5a6b",
"quantity": 1
}/** Command to remove an item from a shopping cart */
export interface RemoveItemFromCart {
/** Unique identifier of the cart */
cartId: string;
/** Identifier of the product to remove */
productId: string;
/** Number of units to remove. If omitted, removes the item entirely. */
quantity?: number;
}{
"$schema": "http://json-schema.org/draft-07/schema#",
"title": "RemoveItemFromCart",
"description": "Command to remove an item from a shopping cart",
"type": "object",
"properties": {
"cartId": {
"description": "Unique identifier of the cart",
"type": "string",
"format": "uuid"
},
"productId": {
"description": "Identifier of the product to remove",
"type": "string",
"format": "uuid"
},
"quantity": {
"description": "Number of units to remove. If omitted, removes the item entirely.",
"type": "integer",
"minimum": 1
}
},
"required": [
"cartId",
"productId"
]
}Request Return
POST /returnsv1.0.0Command sent by a customer to return one or more items from a delivered order.
Request to return items from a delivered order
orderIdstring uuidRequiredcustomerIdstring uuidRequireditemsarray of objectRequired1skustringRequiredquantityintegerRequired1reasonstringRequireddamagedwrong_itemnot_as_describedno_longer_neededothercommentstringOverview
RequestReturn is handled by the Returns API. If the order is within the returns window the request is recorded and Return Requested is published.
Nothing in the catalog.
{
"orderId": "3f6b2b8e-9a4c-4f0e-8f2a-1c2d3e4f5a6b",
"customerId": "3f6b2b8e-9a4c-4f0e-8f2a-1c2d3e4f5a6b",
"items": [
{
"sku": "string",
"quantity": 1
}
],
"reason": "damaged",
"comment": "string"
}/** Request to return items from a delivered order */
export interface RequestReturn {
orderId: string;
customerId: string;
items: {
sku: string;
quantity: number;
}[];
reason: "damaged" | "wrong_item" | "not_as_described" | "no_longer_needed" | "other";
comment?: string;
}{
"$schema": "http://json-schema.org/draft-07/schema#",
"title": "RequestReturn",
"description": "Request to return items from a delivered order",
"type": "object",
"properties": {
"orderId": {
"type": "string",
"format": "uuid"
},
"customerId": {
"type": "string",
"format": "uuid"
},
"items": {
"type": "array",
"minItems": 1,
"items": {
"type": "object",
"properties": {
"sku": {
"type": "string"
},
"quantity": {
"type": "integer",
"minimum": 1
}
},
"required": [
"sku",
"quantity"
]
}
},
"reason": {
"type": "string",
"enum": [
"damaged",
"wrong_item",
"not_as_described",
"no_longer_needed",
"other"
]
},
"comment": {
"type": "string"
}
},
"required": [
"orderId",
"customerId",
"items",
"reason"
]
}Reserve Inventory
POST /reservationsv1.0.0Command to reserve stock for the items in a checked-out cart.
Command to reserve stock for the items in a checked-out cart
cartIdstring uuidRequiredIdentifier of the cart being checked out
customerIdstring uuidIdentifier of the customer checking out
itemsarray of objectRequiredThe items to reserve
productIdstring uuidRequiredquantityintegerRequired1Overview
ReserveInventory is sent by the Checkout Orchestrator to hold stock for the items in a checked-out cart. A successful reservation guarantees the inventory is available while payment is authorized. If a later checkout step fails, the reservation is released.
{
"cartId": "3f6b2b8e-9a4c-4f0e-8f2a-1c2d3e4f5a6b",
"customerId": "3f6b2b8e-9a4c-4f0e-8f2a-1c2d3e4f5a6b",
"items": [
{
"productId": "3f6b2b8e-9a4c-4f0e-8f2a-1c2d3e4f5a6b",
"quantity": 1
}
]
}/** Command to reserve stock for the items in a checked-out cart */
export interface ReserveInventory {
/** Identifier of the cart being checked out */
cartId: string;
/** Identifier of the customer checking out */
customerId?: string;
/** The items to reserve */
items: {
productId: string;
quantity: number;
}[];
}{
"$schema": "http://json-schema.org/draft-07/schema#",
"title": "ReserveInventory",
"description": "Command to reserve stock for the items in a checked-out cart",
"type": "object",
"properties": {
"cartId": {
"description": "Identifier of the cart being checked out",
"type": "string",
"format": "uuid"
},
"customerId": {
"description": "Identifier of the customer checking out",
"type": "string",
"format": "uuid"
},
"items": {
"description": "The items to reserve",
"type": "array",
"items": {
"type": "object",
"properties": {
"productId": {
"type": "string",
"format": "uuid"
},
"quantity": {
"type": "integer",
"minimum": 1
}
},
"required": [
"productId",
"quantity"
]
}
}
},
"required": [
"cartId",
"items"
]
}Submit Review
CMDv1.0.0Broker:KafkaCommand issued by a customer to submit a review and rating for a product.
reviewIdstring uuidRequiredClient-generated id for the review.
productIdstringRequiredThe product being reviewed.
customerIdstringRequiredThe customer submitting the review.
ratingintegerRequiredStar rating from 1 to 5.
1Maximum 5titlestring120bodystringRequired5000submittedAtstring date-timeRequiredOverview
SubmitReview is sent to the Review API when a customer submits a review for a product they have purchased. The API validates and stores the review, then publishes Review Submitted.
Nothing in the catalog.
{
"reviewId": "3f6b2b8e-9a4c-4f0e-8f2a-1c2d3e4f5a6b",
"productId": "string",
"customerId": "string",
"rating": 1,
"title": "string",
"body": "string",
"submittedAt": "2026-01-01T12:00:00Z"
}/** Command issued by a customer to submit a review and rating for a product. */
export interface SubmitReview {
/** Client-generated id for the review. */
reviewId: string;
/** The product being reviewed. */
productId: string;
/** The customer submitting the review. */
customerId: string;
/** Star rating from 1 to 5. */
rating: number;
title?: string;
body: string;
submittedAt: string;
}{
"$schema": "http://json-schema.org/draft-07/schema#",
"title": "SubmitReview",
"type": "object",
"properties": {
"reviewId": {
"type": "string",
"format": "uuid",
"description": "Client-generated id for the review."
},
"productId": {
"type": "string",
"description": "The product being reviewed."
},
"customerId": {
"type": "string",
"description": "The customer submitting the review."
},
"rating": {
"type": "integer",
"minimum": 1,
"maximum": 5,
"description": "Star rating from 1 to 5."
},
"title": {
"type": "string",
"maxLength": 120
},
"body": {
"type": "string",
"maxLength": 5000
},
"submittedAt": {
"type": "string",
"format": "date-time"
}
},
"required": [
"reviewId",
"productId",
"customerId",
"rating",
"body",
"submittedAt"
]
}Update Customer
PATCH /customers/{customerId}v1.0.0Command to update an existing customer's profile.
Command to update an existing customer. Only the fields supplied are changed.
customerIdstring uuidRequiredUnique identifier of the customer to update
emailstring emailNew email address
namestringNew full name
1statusstringNew account status
ACTIVESUSPENDEDCLOSEDOverview
UpdateCustomer is handled by the Customer API. It applies a partial update to an existing customer in the Customer Database and, on success, publishes a Customer Updated event describing what changed.
Nothing in the catalog.
{
"customerId": "3f6b2b8e-9a4c-4f0e-8f2a-1c2d3e4f5a6b",
"email": "jane@example.com",
"name": "string",
"status": "ACTIVE"
}/** Command to update an existing customer. Only the fields supplied are changed. */
export interface UpdateCustomer {
/** Unique identifier of the customer to update */
customerId: string;
/** New email address */
email?: string;
/** New full name */
name?: string;
/** New account status */
status?: "ACTIVE" | "SUSPENDED" | "CLOSED";
}{
"$schema": "http://json-schema.org/draft-07/schema#",
"title": "UpdateCustomer",
"description": "Command to update an existing customer. Only the fields supplied are changed.",
"type": "object",
"properties": {
"customerId": {
"description": "Unique identifier of the customer to update",
"type": "string",
"format": "uuid"
},
"email": {
"description": "New email address",
"type": "string",
"format": "email"
},
"name": {
"description": "New full name",
"type": "string",
"minLength": 1
},
"status": {
"description": "New account status",
"type": "string",
"enum": [
"ACTIVE",
"SUSPENDED",
"CLOSED"
]
}
},
"required": [
"customerId"
]
}Update Product
PATCH /products/{productId}v1.0.0Command to update an existing product in the catalog.
Command to update an existing product. Only the fields supplied are changed.
productIdstring uuidRequiredUnique identifier of the product to update
namestringNew display name
1descriptionstringNew long-form description
priceintegerNew price in minor units (e.g. cents)
0currencystringISO 4217 currency code
^[A-Z]{3}$categorystringNew category
statusstringNew lifecycle status
DRAFTACTIVEARCHIVEDOverview
UpdateProduct is handled by the Product API. It applies a partial update to an existing product in the Product Database and, on success, publishes a Product Updated event describing what changed.
Nothing in the catalog.
{
"productId": "3f6b2b8e-9a4c-4f0e-8f2a-1c2d3e4f5a6b",
"name": "string",
"description": "string",
"price": 0,
"currency": "string",
"category": "string",
"status": "DRAFT"
}/** Command to update an existing product. Only the fields supplied are changed. */
export interface UpdateProduct {
/** Unique identifier of the product to update */
productId: string;
/** New display name */
name?: string;
/** New long-form description */
description?: string;
/** New price in minor units (e.g. cents) */
price?: number;
/** ISO 4217 currency code */
currency?: string;
/** New category */
category?: string;
/** New lifecycle status */
status?: "DRAFT" | "ACTIVE" | "ARCHIVED";
}{
"$schema": "http://json-schema.org/draft-07/schema#",
"title": "UpdateProduct",
"description": "Command to update an existing product. Only the fields supplied are changed.",
"type": "object",
"properties": {
"productId": {
"description": "Unique identifier of the product to update",
"type": "string",
"format": "uuid"
},
"name": {
"description": "New display name",
"type": "string",
"minLength": 1
},
"description": {
"description": "New long-form description",
"type": "string"
},
"price": {
"description": "New price in minor units (e.g. cents)",
"type": "integer",
"minimum": 0
},
"currency": {
"description": "ISO 4217 currency code",
"type": "string",
"pattern": "^[A-Z]{3}$"
},
"category": {
"description": "New category",
"type": "string"
},
"status": {
"description": "New lifecycle status",
"type": "string",
"enum": [
"DRAFT",
"ACTIVE",
"ARCHIVED"
]
}
},
"required": [
"productId"
]
}Vote Review Helpful
CMDv1.0.0Broker:KafkaCommand issued by a customer to mark a published review as helpful (or remove their vote).
reviewIdstring uuidRequiredcustomerIdstringRequiredvotestringRequiredAdd a helpful vote or remove an existing one.
helpfulremovevotedAtstring date-timeRequiredOverview
VoteReviewHelpful is sent to the Review API when a customer marks a review as helpful. The API updates the helpful count and publishes Review Helpful Voted.
Nothing in the catalog.
{
"reviewId": "3f6b2b8e-9a4c-4f0e-8f2a-1c2d3e4f5a6b",
"customerId": "string",
"vote": "helpful",
"votedAt": "2026-01-01T12:00:00Z"
}/** Command issued by a customer to mark a published review as helpful (or remove their vote). */
export interface VoteReviewHelpful {
reviewId: string;
customerId: string;
/** Add a helpful vote or remove an existing one. */
vote: "helpful" | "remove";
votedAt: string;
}{
"$schema": "http://json-schema.org/draft-07/schema#",
"title": "VoteReviewHelpful",
"type": "object",
"properties": {
"reviewId": {
"type": "string",
"format": "uuid"
},
"customerId": {
"type": "string"
},
"vote": {
"type": "string",
"enum": [
"helpful",
"remove"
],
"description": "Add a helpful vote or remove an existing one."
},
"votedAt": {
"type": "string",
"format": "date-time"
}
},
"required": [
"reviewId",
"customerId",
"vote",
"votedAt"
]
}Queries
Requests for information. They return data and change nothing.
Get Customer
GET /customers/{customerId}v1.0.0Query to fetch a single customer by their identifier.
Query to fetch a single customer by their identifier, and the customer returned
requestobjectRequiredParameters used to look up the customer
customerIdstring uuidRequiredUnique identifier of the customer to fetch
responseobjectRequiredThe customer returned by the query
customerIdstring uuidRequiredemailstring emailRequirednamestringstatusstringRequiredACTIVESUSPENDEDCLOSEDregisteredAtstring date-timeOverview
GetCustomer is handled by the Customer API. It returns the current state of a single customer, read directly from the Customer Database.
Nothing in the catalog.
{
"request": {
"customerId": "3f6b2b8e-9a4c-4f0e-8f2a-1c2d3e4f5a6b"
},
"response": {
"customerId": "3f6b2b8e-9a4c-4f0e-8f2a-1c2d3e4f5a6b",
"email": "jane@example.com",
"name": "string",
"status": "ACTIVE",
"registeredAt": "2026-01-01T12:00:00Z"
}
}/** Query to fetch a single customer by their identifier, and the customer returned */
export interface GetCustomer {
/** Parameters used to look up the customer */
request: {
/** Unique identifier of the customer to fetch */
customerId: string;
};
/** The customer returned by the query */
response: {
customerId: string;
email: string;
name?: string;
status: "ACTIVE" | "SUSPENDED" | "CLOSED";
registeredAt?: string;
};
}{
"$schema": "http://json-schema.org/draft-07/schema#",
"title": "GetCustomer",
"description": "Query to fetch a single customer by their identifier, and the customer returned",
"type": "object",
"properties": {
"request": {
"description": "Parameters used to look up the customer",
"type": "object",
"properties": {
"customerId": {
"description": "Unique identifier of the customer to fetch",
"type": "string",
"format": "uuid"
}
},
"required": [
"customerId"
]
},
"response": {
"description": "The customer returned by the query",
"type": "object",
"properties": {
"customerId": {
"type": "string",
"format": "uuid"
},
"email": {
"type": "string",
"format": "email"
},
"name": {
"type": "string"
},
"status": {
"type": "string",
"enum": [
"ACTIVE",
"SUSPENDED",
"CLOSED"
]
},
"registeredAt": {
"type": "string",
"format": "date-time"
}
},
"required": [
"customerId",
"email",
"status"
]
}
},
"required": [
"request",
"response"
]
}Get Order
GET /orders/{orderId}v1.0.0Query to fetch a single order by its identifier.
Query to fetch a single order by its identifier, and the order returned
requestobjectRequiredParameters used to look up the order
orderIdstring uuidRequiredUnique identifier of the order to fetch
responseobjectRequiredThe order returned by the query
orderIdstring uuidRequiredcustomerIdstring uuidRequiredstatusstringRequiredCREATEDCOMPLETEDCANCELLEDitemsarray of objectRequiredproductIdstring uuidRequiredquantityintegerRequired1unitPriceintegerRequiredtotalintegerRequiredOrder total in minor units (e.g. cents)
currencystringRequired^[A-Z]{3}$createdAtstring date-timeOverview
GetOrder is handled by the Order Service. It returns the current state of a single order, read directly from the Order Database.
Nothing in the catalog.
{
"request": {
"orderId": "3f6b2b8e-9a4c-4f0e-8f2a-1c2d3e4f5a6b"
},
"response": {
"orderId": "3f6b2b8e-9a4c-4f0e-8f2a-1c2d3e4f5a6b",
"customerId": "3f6b2b8e-9a4c-4f0e-8f2a-1c2d3e4f5a6b",
"status": "CREATED",
"items": [
{
"productId": "3f6b2b8e-9a4c-4f0e-8f2a-1c2d3e4f5a6b",
"quantity": 1,
"unitPrice": 0
}
],
"total": 0,
"currency": "string",
"createdAt": "2026-01-01T12:00:00Z"
}
}/** Query to fetch a single order by its identifier, and the order returned */
export interface GetOrder {
/** Parameters used to look up the order */
request: {
/** Unique identifier of the order to fetch */
orderId: string;
};
/** The order returned by the query */
response: {
orderId: string;
customerId: string;
status: "CREATED" | "COMPLETED" | "CANCELLED";
items: {
productId: string;
quantity: number;
unitPrice: number;
}[];
/** Order total in minor units (e.g. cents) */
total: number;
currency: string;
createdAt?: string;
};
}{
"$schema": "http://json-schema.org/draft-07/schema#",
"title": "GetOrder",
"description": "Query to fetch a single order by its identifier, and the order returned",
"type": "object",
"properties": {
"request": {
"description": "Parameters used to look up the order",
"type": "object",
"properties": {
"orderId": {
"description": "Unique identifier of the order to fetch",
"type": "string",
"format": "uuid"
}
},
"required": [
"orderId"
]
},
"response": {
"description": "The order returned by the query",
"type": "object",
"properties": {
"orderId": {
"type": "string",
"format": "uuid"
},
"customerId": {
"type": "string",
"format": "uuid"
},
"status": {
"type": "string",
"enum": [
"CREATED",
"COMPLETED",
"CANCELLED"
]
},
"items": {
"type": "array",
"items": {
"type": "object",
"properties": {
"productId": {
"type": "string",
"format": "uuid"
},
"quantity": {
"type": "integer",
"minimum": 1
},
"unitPrice": {
"type": "integer"
}
},
"required": [
"productId",
"quantity",
"unitPrice"
]
}
},
"total": {
"type": "integer",
"description": "Order total in minor units (e.g. cents)"
},
"currency": {
"type": "string",
"pattern": "^[A-Z]{3}$"
},
"createdAt": {
"type": "string",
"format": "date-time"
}
},
"required": [
"orderId",
"customerId",
"status",
"items",
"total",
"currency"
]
}
},
"required": [
"request",
"response"
]
}Get Product
GET /products/{productId}v1.0.0Query to fetch a single product by its identifier.
Query to fetch a single product by its identifier, and the product returned
requestobjectRequiredParameters used to look up the product
productIdstring uuidRequiredUnique identifier of the product to fetch
responseobjectRequiredThe product returned by the query
productIdstring uuidRequiredskustringRequirednamestringRequireddescriptionstringpriceintegerRequiredPrice in minor units (e.g. cents)
currencystringRequired^[A-Z]{3}$categorystringstatusstringRequiredDRAFTACTIVEARCHIVEDOverview
GetProduct is handled by the Product API. It returns the current state of a single product, read directly from the Product Database. Use the Search System when you need to search across many products instead.
Nothing in the catalog.
{
"request": {
"productId": "3f6b2b8e-9a4c-4f0e-8f2a-1c2d3e4f5a6b"
},
"response": {
"productId": "3f6b2b8e-9a4c-4f0e-8f2a-1c2d3e4f5a6b",
"sku": "string",
"name": "string",
"description": "string",
"price": 0,
"currency": "string",
"category": "string",
"status": "DRAFT"
}
}/** Query to fetch a single product by its identifier, and the product returned */
export interface GetProduct {
/** Parameters used to look up the product */
request: {
/** Unique identifier of the product to fetch */
productId: string;
};
/** The product returned by the query */
response: {
productId: string;
sku: string;
name: string;
description?: string;
/** Price in minor units (e.g. cents) */
price: number;
currency: string;
category?: string;
status: "DRAFT" | "ACTIVE" | "ARCHIVED";
};
}{
"$schema": "http://json-schema.org/draft-07/schema#",
"title": "GetProduct",
"description": "Query to fetch a single product by its identifier, and the product returned",
"type": "object",
"properties": {
"request": {
"description": "Parameters used to look up the product",
"type": "object",
"properties": {
"productId": {
"description": "Unique identifier of the product to fetch",
"type": "string",
"format": "uuid"
}
},
"required": [
"productId"
]
},
"response": {
"description": "The product returned by the query",
"type": "object",
"properties": {
"productId": {
"type": "string",
"format": "uuid"
},
"sku": {
"type": "string"
},
"name": {
"type": "string"
},
"description": {
"type": "string"
},
"price": {
"description": "Price in minor units (e.g. cents)",
"type": "integer"
},
"currency": {
"type": "string",
"pattern": "^[A-Z]{3}$"
},
"category": {
"type": "string"
},
"status": {
"type": "string",
"enum": [
"DRAFT",
"ACTIVE",
"ARCHIVED"
]
}
},
"required": [
"productId",
"sku",
"name",
"price",
"currency",
"status"
]
}
},
"required": [
"request",
"response"
]
}Get Product Reviews
QRYv1.0.0Query to fetch the published reviews and aggregate rating for a product.
productIdstringRequiredThe product to fetch reviews for.
pageintegerDefaults to 1.
1pageSizeintegerDefaults to 20.
1Maximum 100sortstringDefaults to newest.
newesthighestlowestmost_helpfulOverview
GetProductReviews is served by the Review API. It returns the published reviews for a product along with its aggregate rating, read from the Review Database and the Rating Cache.
Nothing in the catalog.
{
"productId": "string",
"page": 1,
"pageSize": 20,
"sort": "newest"
}/** Query to fetch the published reviews and aggregate rating for a product. */
export interface GetProductReviews {
/** The product to fetch reviews for. */
productId: string;
page?: number;
pageSize?: number;
sort?: "newest" | "highest" | "lowest" | "most_helpful";
}{
"$schema": "http://json-schema.org/draft-07/schema#",
"title": "GetProductReviews",
"type": "object",
"properties": {
"productId": {
"type": "string",
"description": "The product to fetch reviews for."
},
"page": {
"type": "integer",
"minimum": 1,
"default": 1
},
"pageSize": {
"type": "integer",
"minimum": 1,
"maximum": 100,
"default": 20
},
"sort": {
"type": "string",
"enum": [
"newest",
"highest",
"lowest",
"most_helpful"
],
"default": "newest"
}
},
"required": [
"productId"
]
}Get Stock Level
GET /stock/{productId}v1.0.0Query to fetch the current available stock level for a product.
Query to fetch the current available stock level for a product, and the level returned
requestobjectRequiredproductIdstring uuidRequiredresponseobjectRequiredproductIdstring uuidRequiredavailableintegerRequired0reservedinteger0Overview
GetStockLevel is handled by the Inventory Service. It returns the current available stock for a product, read directly from the Inventory Database.
Nothing in the catalog.
{
"request": {
"productId": "3f6b2b8e-9a4c-4f0e-8f2a-1c2d3e4f5a6b"
},
"response": {
"productId": "3f6b2b8e-9a4c-4f0e-8f2a-1c2d3e4f5a6b",
"available": 0,
"reserved": 0
}
}/** Query to fetch the current available stock level for a product, and the level returned */
export interface GetStockLevel {
request: {
productId: string;
};
response: {
productId: string;
available: number;
reserved?: number;
};
}{
"$schema": "http://json-schema.org/draft-07/schema#",
"title": "GetStockLevel",
"description": "Query to fetch the current available stock level for a product, and the level returned",
"type": "object",
"properties": {
"request": {
"type": "object",
"properties": {
"productId": {
"type": "string",
"format": "uuid"
}
},
"required": [
"productId"
]
},
"response": {
"type": "object",
"properties": {
"productId": {
"type": "string",
"format": "uuid"
},
"available": {
"type": "integer",
"minimum": 0
},
"reserved": {
"type": "integer",
"minimum": 0
}
},
"required": [
"productId",
"available"
]
}
},
"required": [
"request",
"response"
]
}Search Products
GET /search/productsv1.0.0Query to search the catalog for products matching a term, with optional filters and pagination.
Query to search the catalog for products, and the paginated result returned
requestobjectRequiredSearch parameters
querystringRequiredFree-text search term
1filtersobjectOptional filters applied to the search
categorystringstatusstringDRAFTACTIVEARCHIVEDminPriceintegerMinimum price in minor units (e.g. cents)
0maxPriceintegerMaximum price in minor units (e.g. cents)
0pageinteger1-based page number Defaults to 1.
1pageSizeintegerNumber of results per page Defaults to 20.
1Maximum 100responseobjectRequiredPaginated search results
totalintegerRequiredTotal number of products matching the query
pageintegerRequiredpageSizeintegerRequiredresultsarray of objectRequiredproductIdstring uuidRequiredskustringRequirednamestringRequiredcategorystringpriceintegerPrice in minor units (e.g. cents)
currencystring^[A-Z]{3}$scorenumberRelevance score for this result
Overview
SearchProducts is handled by the Search API. It runs a full-text search over the Search Index and returns a paginated list of matching products. Use this whenever you need to find products across the catalog, rather than fetching a single product by id with Get Product.
Nothing in the catalog.
{
"request": {
"query": "string",
"filters": {
"category": "string",
"status": "DRAFT",
"minPrice": 0,
"maxPrice": 0
},
"page": 1,
"pageSize": 20
},
"response": {
"total": 0,
"page": 0,
"pageSize": 0,
"results": [
{
"productId": "3f6b2b8e-9a4c-4f0e-8f2a-1c2d3e4f5a6b",
"sku": "string",
"name": "string",
"category": "string",
"price": 0,
"currency": "string",
"score": 0
}
]
}
}/** Query to search the catalog for products, and the paginated result returned */
export interface SearchProducts {
/** Search parameters */
request: {
/** Free-text search term */
query: string;
/** Optional filters applied to the search */
filters?: {
category?: string;
status?: "DRAFT" | "ACTIVE" | "ARCHIVED";
/** Minimum price in minor units (e.g. cents) */
minPrice?: number;
/** Maximum price in minor units (e.g. cents) */
maxPrice?: number;
};
/** 1-based page number */
page?: number;
/** Number of results per page */
pageSize?: number;
};
/** Paginated search results */
response: {
/** Total number of products matching the query */
total: number;
page: number;
pageSize: number;
results: {
productId: string;
sku: string;
name: string;
category?: string;
/** Price in minor units (e.g. cents) */
price?: number;
currency?: string;
/** Relevance score for this result */
score?: number;
}[];
};
}{
"$schema": "http://json-schema.org/draft-07/schema#",
"title": "SearchProducts",
"description": "Query to search the catalog for products, and the paginated result returned",
"type": "object",
"properties": {
"request": {
"description": "Search parameters",
"type": "object",
"properties": {
"query": {
"description": "Free-text search term",
"type": "string",
"minLength": 1
},
"filters": {
"description": "Optional filters applied to the search",
"type": "object",
"properties": {
"category": {
"type": "string"
},
"status": {
"type": "string",
"enum": [
"DRAFT",
"ACTIVE",
"ARCHIVED"
]
},
"minPrice": {
"description": "Minimum price in minor units (e.g. cents)",
"type": "integer",
"minimum": 0
},
"maxPrice": {
"description": "Maximum price in minor units (e.g. cents)",
"type": "integer",
"minimum": 0
}
}
},
"page": {
"description": "1-based page number",
"type": "integer",
"minimum": 1,
"default": 1
},
"pageSize": {
"description": "Number of results per page",
"type": "integer",
"minimum": 1,
"maximum": 100,
"default": 20
}
},
"required": [
"query"
]
},
"response": {
"description": "Paginated search results",
"type": "object",
"properties": {
"total": {
"description": "Total number of products matching the query",
"type": "integer"
},
"page": {
"type": "integer"
},
"pageSize": {
"type": "integer"
},
"results": {
"type": "array",
"items": {
"type": "object",
"properties": {
"productId": {
"type": "string",
"format": "uuid"
},
"sku": {
"type": "string"
},
"name": {
"type": "string"
},
"category": {
"type": "string"
},
"price": {
"description": "Price in minor units (e.g. cents)",
"type": "integer"
},
"currency": {
"type": "string",
"pattern": "^[A-Z]{3}$"
},
"score": {
"description": "Relevance score for this result",
"type": "number"
}
},
"required": [
"productId",
"sku",
"name"
]
}
}
},
"required": [
"total",
"page",
"pageSize",
"results"
]
}
},
"required": [
"request",
"response"
]
}Channels
Where messages travel: topics, queues and endpoints.
Discount Commands
v1.0.0SQS queue used to send discount calculation commands to the Promotion Service.
Overview
The Cart API sends Calculate Discount commands to this queue, and the Promotion Service consumes them.
- Address
- shopping-discount-commands
- Protocols
- sqs
- Delivery
- at-least-once
- Messages
- 1
Loyalty Events
v1.0.0Kafka topic that carries loyalty points events from the Loyalty System.
Loyalty Service → nobody yet
Overview
The Loyalty Service publishes Loyalty Points Earned and Loyalty Points Reversed to this topic as customers earn and lose points.
| Consumer | Domain | Why |
|---|---|---|
| Promotion Service | Shopping | Offers promotions based on a customer's points. |
| Notification Service | Customer (Notifications) | Tells the customer about the points they've earned. |
- Address
- customer.loyalty-events
- Protocols
- kafka
- Delivery
- at-least-once
- Messages
- 2
Order Events
v1.0.0Kafka topic that carries order lifecycle events from the Order Management System to the rest of Acme Inc.
Order Service → nobody yet
Overview
The Order Service publishes the order lifecycle to this topic: Order Created, Order Confirmed, Order Completed and Order Cancelled. Other domains subscribe to it rather than calling the Ordering domain directly:
| Consumer | Domain | Why |
|---|---|---|
| Warehouse Service | Fulfilment | Starts picking once an order completes. |
| Loyalty Service | Customer (Loyalty) | Awards points for completed orders and reverses them for cancelled ones. |
| Notification Service | Customer (Notifications) | Tells the customer their order is confirmed. |
- Address
- ordering.order-events
- Protocols
- kafka
- Delivery
- at-least-once
- Messages
- 4
Payment Outcomes
v1.0.0HTTP webhook channel used to deliver payment and refund outcomes from Stripe.
Overview
The Webhook Endpoint delivers payment and refund outcome events through this webhook channel. The Payment Worker consumes payment success and failure events from it.
- Address
- /webhooks/stripe
- Protocols
- http
- Delivery
- at-least-once
- Messages
- 3
Product Events
v1.0.0Kafka topic that carries product lifecycle events from the Product Catalog System.
Overview
The Product Search Publisher publishes product lifecycle events to this topic. Events needed by the Search System are routed to the Search Product Events topic for downstream processing.
- Address
- catalog.product-events
- Protocols
- kafka
- Delivery
- at-least-once
- Messages
- 3
Returns
v1.0.0Kafka topic that carries return events from the Returns System as a return moves from request to receipt.
Overview
The Returns System publishes the lifecycle of a return to this topic. The Returns API publishes Return Requested, and the Returns Processor publishes Return Approved and Return Received.
| Consumer | Domain | Why |
|---|---|---|
| Returns Processor | Fulfilment (Returns) | Reviews new return requests. |
| Payment Worker | Payments | Refunds the customer once the items are received. |
| Inventory Service | Fulfilment | Restocks returned items. |
| Notification Service | Customer (Notifications) | Tells the customer their return is approved. |
- Address
- fulfilment.returns
- Protocols
- kafka
- Delivery
- at-least-once
- Messages
- 3
Search Indexer Queue
v1.0.0SQS queue from which the Search Indexer consumes product lifecycle events.
Overview
The Search Indexer consumes product events from this queue and applies them to the search index. The queue is the final channel in the product-event routing chain.
- Address
- catalog-search-indexer
- Protocols
- sqs
- Delivery
- at-least-once
- Messages
- 3
Search Product Events
v1.0.0Filtered Kafka topic containing product changes that must be applied to the search index.
No messages in the catalog use this channel.
Overview
This topic receives the search-relevant subset of product events from Product Events and routes them to the Search Indexer Queue queue.
- Address
- catalog.product-events.search
- Protocols
- kafka
- Delivery
- at-least-once
- Messages
- 0
Data stores
Where data lives: databases, caches, object stores and warehouses.
Cart Database
System of recordv1.0.0PostgreSQL database that is the system of record for shopping carts and their items.
System of record for shopping carts
What is this?
The Cart Database is the authoritative store for shopping carts at Acme Inc. The Cart API reads from and writes to it as customers add, remove and check out items.
What does it store?
- Carts — one row per cart: id, customer, status and timestamps.
- Cart Items — one row per item in a cart: product, quantity and unit price.
Retention
Carts are transient. Abandoned carts are pruned after 90 days (see frontmatter). A checked-out cart's contents live on in the Cart Checked Out event and downstream order records.
- Type
- database
- Technology
- postgres@16
- Access
- readWrite
- Classification
- internal
- Residency
- eu-west-1
- Retention
- 90d
- System of record
- Yes
Customer Database
System of recordv1.0.0PostgreSQL database that is the system of record for all customer profile data.
System of record for customer profiles
What is this?
The Customer Database is the authoritative store for every customer profile at Acme Inc. The Customer API reads from and writes to it. It stores profile data only — credentials and authentication live in the Identity Provider's User Directory, not here.
What does it store?
- Customers — one row per customer: id, email, name and account status.
Access patterns
- The Customer API is the only writer on the request path.
- No credentials or passwords are stored here — only profile data. Authentication is owned by the Identity Provider.
Classification
Customer profile data is confidential. Access is role-based and least-privilege; PII handling follows Acme's data policies.
- Type
- database
- Technology
- postgres@16
- Access
- readWrite
- Classification
- confidential
- Residency
- eu-west-1
- Retention
- indefinite
- System of record
- Yes
Inventory Database
System of recordv1.0.0PostgreSQL database that is the system of record for stock levels and reservations.
System of record for stock levels and reservations
What is this?
The Inventory Database is the authoritative store for stock levels at Acme Inc. The Inventory Service reads from and writes to it as stock is reserved and released.
What does it store?
- Stock — one row per product: available quantity and reserved quantity.
- Reservations — one row per reservation: id, order, items and status.
- Type
- database
- Technology
- postgres@16
- Access
- readWrite
- Classification
- internal
- Residency
- eu-west-1
- Retention
- 3y
- System of record
- Yes
Loyalty Database
System of recordv1.0.0PostgreSQL database that holds the loyalty points ledger and each customer's points balance.
System of record for loyalty points transactions and balances
What is this?
The Loyalty Database is the authoritative store for loyalty points. The Loyalty Service appends a ledger entry for every award or reversal and keeps a running balance per customer.
What does it store?
- Points ledger — one row per award or reversal, linked to the order that caused it.
- Balances — current points balance and tier per customer.
- Type
- database
- Technology
- postgres@16
- Access
- readWrite
- Classification
- internal
- Residency
- eu-west-1
- Retention
- 7y
- System of record
- Yes
Notification Preferences
System of recordv1.0.0PostgreSQL database holding each customer's notification channels, opt-ins and quiet hours.
System of record for customer notification and marketing consent preferences
What is this?
The Notification Preferences store records how each customer wants to be contacted. The Notification Service reads it before every send so customers only hear from us on channels they have opted into.
What does it store?
- Channels — email address, phone number and push tokens, with per-channel opt-in.
- Topics — which notification types (orders, delivery, loyalty, reviews) the customer wants.
- Quiet hours — times when non-urgent notifications are held back.
- Type
- database
- Technology
- postgres@16
- Access
- readWrite
- Classification
- confidential
- Residency
- eu-west-1
- Retention
- indefinite
- System of record
- Yes
Nothing in the catalog writes to it.
Order Database
System of recordv1.0.0PostgreSQL database that is the system of record for orders and their items.
System of record for orders
What is this?
The Order Database is the authoritative store for orders at Acme Inc. The Order Service reads from and writes to it as orders are created, cancelled and completed.
What does it store?
- Orders — one row per order: id, customer, status, total and timestamps.
- Order Items — one row per item in an order: product, quantity and unit price.
Retention
Orders are financial records and are retained for 7 years (see frontmatter) to meet accounting and audit requirements.
- Type
- database
- Technology
- postgres@16
- Access
- readWrite
- Classification
- confidential
- Residency
- eu-west-1
- Retention
- 7y
- System of record
- Yes
Payment Database
System of recordv1.0.0PostgreSQL database that is the system of record for payments and refunds.
System of record for payments and refunds
What is this?
The Payment Database is the authoritative store for payments and refunds at Acme Inc. The Payment API and Payment Worker read from and write to it as payments are authorized, charged and refunded.
What does it store?
- Payments — one row per payment: id, order, amount, status and timestamps.
- Refunds — one row per refund: id, payment, amount, status and timestamps.
Retention
Payments and refunds are financial records and are retained for 7 years (see frontmatter) to meet accounting and audit requirements.
- Type
- database
- Technology
- postgres@16
- Access
- readWrite
- Classification
- confidential
- Residency
- eu-west-1
- Retention
- 7y
- System of record
- Yes
Product Database
System of recordv1.0.0PostgreSQL database that is the system of record for all product data.
System of record for products, plus the change outbox used to publish events
What is this?
The Product Database is the authoritative store for every product in the catalog. The Product API reads from and writes to it, and the Product Worker uses it for asynchronous enrichment. It also holds the outbox table that the Product Search Publisher reads to publish product change events.
What does it store?
- Products — one row per product: SKU, name, description, price, currency, category and lifecycle status.
- Outbox — one row per product change, used to reliably publish Product Created, Product Updated and Product Deleted events.
Access patterns
- The Product API is the only writer to the
productstable on the request path. - The Product Search Publisher is a read-only consumer of the
outboxtable. - The Product Worker reads and writes for asynchronous enrichment jobs.
Why an outbox?
Writing the product change and the event in the same transaction guarantees we never persist a change without an event, or publish an event for a change that rolled back. The publisher reads the outbox and emits events with at-least-once delivery.
- Type
- database
- Technology
- postgres@16
- Access
- readWrite
- Classification
- internal
- Residency
- eu-west-1
- Retention
- indefinite
- System of record
- Yes
Promotion Database
System of recordv1.0.0PostgreSQL store of promotion and discount rules.
System of record for promotion and discount rules
What is this?
The Promotion Database holds the promotion and discount rules that the Promotion Service evaluates when pricing a cart. It is the source of truth for what promotions exist, who they apply to, and when they are valid.
What does it store?
- Promotions — one row per promotion: code, type (percentage / fixed amount), value, and validity window.
- Eligibility rules — the conditions under which a promotion applies (minimum spend, customer segment, etc.).
Access patterns
- The Promotion Service reads rules when handling Calculate Discount.
- Rules are managed by the promotions team and change infrequently relative to read volume.
- Type
- database
- Technology
- postgres@16
- Access
- readWrite
- Classification
- internal
- Residency
- eu-west-1
- Retention
- indefinite
- System of record
- Yes
Nothing in the catalog writes to it.
Rating Cache
v1.0.0Redis cache that serves each product's aggregate star rating with low latency.
Fast read store for aggregate product ratings
What is this?
The Rating Cache holds the aggregate rating (average score and review count) for each product. It is a derived read model — never a source of truth — so it can be rebuilt at any time by replaying published reviews.
What does it store?
- Aggregate rating — one entry per product: average rating, review count and last-updated timestamp.
Access patterns
- The Rating Aggregator writes the aggregate rating whenever a review is published.
- The Review API reads it to serve Get Product Reviews.
- Type
- cache
- Technology
- redis@7
- Access
- readWrite
- Classification
- internal
- Residency
- eu-west-1
- Retention
- transient
- System of record
- No
Returns Database
System of recordv1.0.0PostgreSQL database that is the system of record for return requests and their status.
System of record for customer returns and their lifecycle
What is this?
The Returns Database stores every return request. The Returns API writes new requests, and the Returns Processor reads them and records approval and receipt.
What does it store?
- Returns — one row per return: order, customer, reason and status (
requested,approved,received). - Return items — SKUs, quantities and inspected condition.
- Type
- database
- Technology
- postgres@16
- Access
- readWrite
- Classification
- internal
- Residency
- eu-west-1
- Retention
- 7y
- System of record
- Yes
Review Database
System of recordv1.0.0PostgreSQL database that is the system of record for reviews and their moderation state.
System of record for reviews, ratings and moderation decisions
What is this?
The Review Database is the authoritative store for every review in the Reviews & Ratings domain. The Review API writes new reviews to it, and the Review Moderation Worker records each moderation decision against the stored review.
What does it store?
- Reviews — one row per review: product, customer, rating, title, body and lifecycle status (
submitted,published,rejected). - Moderation decisions — the outcome and reason for each moderated review, kept for audit.
Access patterns
- The Review API writes new reviews and reads published reviews.
- The Review Moderation Worker reads submitted reviews and writes moderation outcomes.
- The Rating Aggregator reads published reviews to recompute aggregates.
- Type
- database
- Technology
- postgres@16
- Access
- readWrite
- Classification
- internal
- Residency
- eu-west-1
- Retention
- indefinite
- System of record
- Yes
Search Index
v1.0.0The denormalised, search-optimised index of products that powers product search.
Serve fast, relevant product search
What is this?
The Search Index is a denormalised, search-optimised copy of the catalog. It is not a source of truth — it can be rebuilt at any time by replaying product events from the Product Catalog System. The Search Indexer keeps it up to date, and the Search API reads from it to answer Search Products queries.
What does it store?
One document per product, optimised for search:
- Searchable text — name and description, analysed for full-text matching.
- Filterable fields — category, status, price, currency.
- A relevance signal used to rank results.
Why is it not authoritative?
The system of record is the Product Database. The index is a derived read model: if it is ever lost or corrupted, we rebuild it by replaying Product Created, Product Updated and Product Deleted events. This keeps search fast without coupling other teams to the catalog database.
Operational notes
- Rebuildable: a full reindex is a supported, routine operation.
- Eventually consistent: changes appear in search shortly after the Search Indexer processes the corresponding event.
- Type
- searchIndex
- Technology
- opensearch@2
- Access
- readWrite
- Classification
- internal
- Residency
- eu-west-1
- Retention
- rebuildable
- System of record
- No
User Directory
System of recordv1.0.0The directory of customer credentials and identities — the source of truth for authentication.
System of record for credentials and login identities
What is this?
The User Directory is the authoritative store for customer credentials and login identities. The OAuth API reads from it to verify sign-in attempts. It holds only authentication data — customer profile data lives separately in the Customer Management System's Customer Database.
What does it store?
- Identities — one record per customer: the login email and a securely hashed credential.
- Login metadata — last login time, multi-factor settings, lockout state.
Why is it separate from the customer profile?
Keeping credentials in a dedicated, regulated-classification store isolates the most sensitive data from general profile data. Authentication is owned by the Identity Provider; the Customer Management System never sees raw credentials.
Security
- Credentials are stored only as salted, hashed values — never in plaintext.
- Access is tightly restricted to the OAuth API under least-privilege roles.
- Type
- database
- Technology
- postgres@16
- Access
- readWrite
- Classification
- regulated
- Residency
- eu-west-1
- Retention
- indefinite
- System of record
- Yes
Nothing in the catalog writes to it.
Warehouse Database
System of recordv1.0.0PostgreSQL database that stores picking jobs and their status.
System of record for picking and packing jobs
What is this?
The Warehouse Database stores the picking and packing jobs for the warehouse. The Warehouse Service creates jobs and the Picking Worker updates them as orders are picked.
What does it store?
- Picking Jobs — one row per order being fulfilled: order, status and timestamps.
- Picking Job Items — the items to pick for each job.
- Type
- database
- Technology
- postgres@16
- Access
- readWrite
- Classification
- internal
- Residency
- eu-west-1
- Retention
- 1y
- System of record
- Yes
Flows
How the pieces work together, step by step.
Checkout Saga
v1.0.0How the Checkout Orchestrator turns a checked-out cart into an order — reserving inventory, authorizing payment and creating the order, with compensation when a step fails.
- EVTCart Checked OutReceive checkout
- SVCCheckout APIStart saga
- SVCCheckout OrchestratorStep 1 — reserve inventory
- CMDReserve InventoryReserved → Authorize PaymentOut of stock → Compensate
- CMDAuthorize PaymentAuthorized → Create OrderDeclined → Compensate
- CMDCreate OrderOrder created
- ACTORSaga complete
- ACTORCompensate and abort
Overview
The Checkout Saga is the heart of the Checkout System. It coordinates the steps that turn a checked-out cart into a confirmed order. Each step has a compensating action so a failure never leaves the customer in an inconsistent state.
Steps
- Reserve inventory — Reserve Inventory holds stock for the cart's items.
- Authorize payment — Authorize Payment places a hold on the order total.
- Create order — Create Order persists the order in the Order Management System.
If reservation or authorization fails, the orchestrator compensates — releasing the reservation and voiding the authorization — and aborts without creating an order.
Order Cancellation
v1.0.0How an order is cancelled — whether requested by the customer or triggered by a failure — and the events that tell the rest of the business to unwind it.
- ACTORShopper or System
A customer asks to cancel, or a downstream failure (payment, inventory) forces a cancellation.
Cancel order - CMDCancel OrderHandle cancellation
- SVCOrder ServiceCheck eligibility → Cancellation policy checkAlready completed → Cannot cancel
- ACTORCancellation policyMark cancelled
- DBOrder DatabasePersist + publish
- EVTOrder CancelledUnwind downstream
- ACTORRelease and refund
- ACTORCannot cancel
Overview
Order Cancellation documents how the Order Management System cancels an order. Cancellation can be requested by a shopper or forced by a downstream failure during checkout. Only orders that have not yet completed can be cancelled.
How it works
- A Cancel Order command reaches the Order Service.
- The service checks the cancellation policy — only
CREATEDorders are cancellable. - If eligible, the order is marked cancelled in the Order Database and Order Cancelled is published.
- Downstream consumers react to Order Cancelled to release inventory, refund payment and stop fulfilment.
- If the order is already completed, cancellation is rejected and the customer is sent to the returns process.
Order to Doorstep
v1.0.0End-to-endCross-domainThe end-to-end journey of an order, from a shopper finding a product to the parcel arriving at their door — and what happens when payment fails, stock runs out, delivery goes wrong or the customer sends it back. Crosses every business domain in the catalog.
- ACTORShopper
A customer browsing the storefront on web or mobile.
Searches the catalog - QRY
- SVCSearch APIShopper picks a product
- CMDAdd Item To CartAdd to basket
- SVC
- CMDCheckout CartSign in first
- CMDAuthenticate CustomerVerify session
- SVC
- EVTCustomer AuthenticatedContinue checkout
- SVC
- QRYGet ProductQuery
- SVCProduct APIPrices returned
- CMDCalculate DiscountApply promotions
- SVCPromotion ServiceCodes and offers applied
- EVTDiscount CalculatedFinal total known
- EVTCart Checked OutHand over to Ordering
- SVCCheckout APIStart checkout saga
- SVCCheckout Orchestrator
Coordinates stock, payment and order creation, compensating if any step fails.
Step 1 — hold the stock - CMDReserve InventoryReserve items
- SVCInventory ServiceIn stock → Inventory ReservedOut of stock → Inventory Unavailable
- EVTInventory ReservedStep 2 — take payment → Authorize Payment
- EVTInventory UnavailableAbort checkout → Order Cancellation
- CMDAuthorize PaymentCharge the order total
- SVCPayment APIQueue the payment
- EVTPayment RequestedScreen for fraud
- SVCFraud API
A third-party fraud service scores the payment before any money moves.
Low risk → Fraud Check PassedHigh risk → Fraud Check Failed - EVTFraud Check FailedBlock and abort → Order Cancellation
- EVTFraud Check PassedCharge card
- SVCPayments APIResult via webhook
- SVCWebhook EndpointCard charged → Payment SucceededCard declined → Payment Failed
- EVTPayment FailedAbort checkout → Order Cancellation
- EVTPayment SucceededStep 3 — create the order → Create OrderBook the revenue → Ledger Exporter
- SVCLedger Exporter
Posts the payment to the finance ledger for reporting and reconciliation.
- FLWOrder Cancellation
Releases held stock, voids any payment and tells the customer. Click to expand the sub-flow.
Checkout aborted - ACTOROrder not placed
- CMDCreate OrderPersist the order
- SVCOrder ServiceOrder placed
- EVTOrder Confirmed
The moment the sale is real. Three domains react to it in parallel.
Award points → Loyalty ServiceEmail confirmation → Notification ServiceStart fulfilment → Warehouse Service - SVCLoyalty ServicePoints credited
- EVT
- SVCNotification ServiceConfirmation sent
- EVT
- SVCWarehouse ServiceCreate pick list
- SVCPicking WorkerItems boxed
- EVTOrder PackedReady at the dock
- EVTOrder Ready For ShippingBook a courier
- CMDCreate ShipmentPick the cheapest carrier
- SVCCarrier AdapterParcel handed over
- SVC
- EVTShipment CreatedDelivered → Shipment DeliveredDelivery failed → Shipment Failed
- EVTShipment FailedNeeds a human
- ACTORDelivery exceptionTell the customer
- SVCNotification Service
Emails the customer that their parcel is delayed and what happens next.
- EVTShipment DeliveredClose the order
- EVTOrder CompletedHappy path → Order deliveredCustomer reviews it → Submit ReviewCustomer sends it back → Request Return
- ACTOROrder delivered
- CMDSubmit ReviewRate the product
- SVCReview APIQueued for moderation
- EVTReview SubmittedRecalculate stars
- SVCRating AggregatorNew average
- EVT
- CMDRequest ReturnStart a return
- SVCReturns APIReturn label issued
- EVTReturn RequestedParcel comes back
- SVCReturns ProcessorItem inspected
- EVTReturn ApprovedRefund the customer
- SVCPayment WorkerIssue refund
- EVTRefund RequestedRefund the card
- SVCPayments APIMoney returned
- EVTRefund ProcessedTake back points
- SVCLoyalty ServicePoints removed
- EVTLoyalty Points ReversedReturn closed
- ACTORReturn complete
Overview
Order to Doorstep follows a single order across the whole business — from a shopper searching the catalog to the parcel arriving at their door. It's the best flow in this catalog for seeing how the domains fit together:
| Domain | What it does in this flow |
|---|---|
| Shopping | Holds the basket and applies promotions |
| Catalog | Search and live product prices |
| Customer | Signs the shopper in, awards loyalty points and sends emails (the Loyalty and Notifications subdomains) |
| Ordering | Runs the checkout saga and owns the order |
| Payments | Fraud screening, charging the card via Stripe and booking revenue |
| Fulfilment | Stock, picking, packing, shipping — and the Returns subdomain |
| Reviews | Ratings once the order arrives |
Try it
- Group by (top right) — group the steps by Domain, System, Team or Domain › System to see where work hands over between teams. Switch between Boxes and Lanes.
- Walk through (bottom left) — step through the order one hop at a time. At each branch, pick what happens next: in stock or out of stock, card charged or declined, delivered or failed, reviewed or returned.
- Order Cancellation is a sub-flow — click it to expand the compensation steps in place.
Paths through the flow
- Happy path — search, basket, sign in, price, reserve stock, pass fraud checks, charge the card, create the order, then loyalty, email and fulfilment run in parallel until the parcel is delivered.
- Checkout aborted — out of stock, high fraud risk or a declined card all hand over to the Order Cancellation sub-flow.
- Delivery exception — the courier fails to deliver and support takes over.
- Review — the customer rates the product and the average rating updates.
- Return — the item comes back, the card is refunded and loyalty points are reversed.
Place an Order
v1.0.0The end-to-end journey from a customer checking out their cart to a confirmed order — spanning the Shopping and Ordering domains, including the checkout saga and its failure path.
- ACTORShopper
The customer confirms their cart and starts checkout.
Check out cart - CMDCheckout CartPrice and finalise cart
- SVCCart APIPublish checkout
- EVTCart Checked OutStart checkout flow
- SVCCheckout APIRun checkout saga
- SVCCheckout OrchestratorReserve inventory → Reserve InventoryAuthorize payment → Authorize Payment
- CMDReserve InventoryInventory held
- CMDAuthorize PaymentPayment authorized → Create OrderAuthorization declined → Checkout failed
- CMDCreate OrderPersist order
- SVCOrder ServicePublish order created
- EVTOrder CreatedConfirm to customer
- ACTOROrder confirmed
- ACTORCheckout failedCancel order
- EVT
Overview
Place an Order is the headline business flow at Acme Inc. It begins in the Shopping domain, when a shopper checks out their cart, and finishes in the Ordering domain, with a confirmed order — or a compensated, cancelled one if a step fails.
How it works
- The shopper checks out — the Cart API prices the cart and publishes Cart Checked Out.
- The Checkout API picks this up and hands it to the Checkout Orchestrator.
- The orchestrator runs the saga: Reserve Inventory then Authorize Payment.
- On success it sends Create Order to the Order Service, which publishes Order Created.
- If any step fails, the orchestrator compensates the earlier steps and the order is cancelled via Order Cancelled.
Product Launch
v1.0.0Cross-domainLaunch checklistHow a new product goes from a merchandiser's draft to live on the storefront — enriched, indexed for search, stocked, given a launch offer and announced to customers — and how it's pulled if customers report a fault.
- ACTORMerchandiser
Someone on the trading team adding a new product to the range.
Submits the new product - CMDCreate ProductCreate
- SVCProduct API
Validates the product and saves it with an outbox record in one transaction.
Valid → Product DatabaseMissing data → Rejected - ACTORRejected
- DBProduct DatabaseOutbox publishes
- EVTProduct Created
Three teams pick the new product up in parallel.
Enrich → Product WorkerCheck stock → Get Stock LevelSet a launch offer → Calculate Discount - SVCProduct Worker
Generates image renditions and variant data for the new product.
Images and variants added - EVTProduct UpdatedIndex for search
- FLW
- DBSearch IndexSearchable → Launch checklist
- QRYGet Stock LevelQuery
- SVCInventory ServiceStock received → Launch checklistNothing in the warehouse → Awaiting stock
- ACTORAwaiting stock
- CMDCalculate Discount10% launch week offer
- SVCPromotion ServiceOffer scheduled
- EVTDiscount CalculatedOffer live
- ACTORLaunch checklistAnnounce the launch
- SVC
- EVTCustomer NotifiedOpens the email
- ACTORShopper
A customer who clicked through from the launch email.
Searches for it - QRYSearch ProductsQuery
- SVCSearch APIOpens the product page
- QRYGet ProductQuery
- SVCProduct APILoad reviews
- QRYGet Product ReviewsQuery
- SVCReview APIGood reviews → Product liveCustomers report a fault → Flag Review
- ACTORProduct live
- CMDFlag ReviewReport a safety issue
- EVTReview FlaggedMerchandiser pulls it
- CMDDelete ProductWithdraw
- SVCProduct APIRemoved from the range
- EVTProduct DeletedDropped from search
- ACTORProduct withdrawn
Overview
Product Launch follows a new product from a merchandiser's draft to selling on the storefront. It's a good flow for showing how several teams work on the same event in parallel, and how their work comes together before launch.
| Domain | What it does in this flow |
|---|---|
| Catalog | Creates and enriches the product, and gets it into search |
| Fulfilment | Confirms there's stock to sell |
| Shopping | Sets up the launch week offer |
| Customer | Announces the launch (the Notifications subdomain) |
| Reviews | Shows reviews — and raises the alarm if something's wrong |
Try it
- Group by (top right) — try Team: three teams react to one
ProductCreatedevent in parallel, then their work comes together at the launch checklist. - Walk through (bottom left) — step through the launch. At each branch, pick what happens next: valid or missing data, stock or no stock, good reviews or a reported fault.
- Product Search Indexing is a sub-flow — click it to expand how the product gets into search.
Paths through the flow
- Launch — the product is created and saved, then enriched and indexed, stocked and given a launch offer in parallel. Once all three are done it's announced, and shoppers find it through search.
- Rejected — the product is missing required details and goes back to the merchandiser.
- Awaiting stock — nothing is in the warehouse yet, so the launch waits.
- Recall — customers report a fault and the product is pulled from the storefront and search.
Product Search Indexing
v1.0.0How a change to a product in the catalog reliably flows into the search index — via the outbox, product events and the indexer — so search stays in sync without coupling to the catalog database.
- ACTORMerchant
A merchant creates or updates a product in the catalog.
Apply change - SVCProduct APIWrite change + outbox row
- DBProduct DatabaseOutbox row committed
- ACTORTransactional outboxDrain outbox
- SVCProduct Search PublisherCreated → Product CreatedUpdated → Product UpdatedDeleted → Product Deleted
- EVTProduct CreatedIndex product → Search Indexer
- EVTProduct UpdatedRe-index product → Search Indexer
- EVTProduct DeletedRemove from index
- SVCSearch IndexerApply to index
- DBSearch IndexAvailable to search
- ACTORProduct is searchable
Overview
Product Search Indexing documents how the Search System keeps its index in sync with the catalog. The search index is a derived read model — never a source of truth — so it can be rebuilt at any time by replaying product events.
How it works
- A merchant changes a product via the Product API, which writes the change and an outbox row to the Product Database in one transaction.
- The Product Search Publisher reliably drains the outbox and publishes Product Created, Product Updated or Product Deleted.
- The Search Indexer consumes those events and applies them to the Search Index.
- The change is now searchable via the Search API — with no direct coupling between search and the catalog database.
Review Submission
v1.0.0How a customer's product review travels from submission, through moderation, to being published and folded into the product's aggregate rating.
- ACTORCustomer
A customer writes a review and rating for a product they purchased.
Submit review - SVCReview APIStore review
- DBReview DatabaseReview stored
- EVTReview SubmittedScreen review
- SVCReview Moderation WorkerApproved → Review PublishedRejected → Review Rejected
- EVTReview PublishedUpdate rating → Rating Aggregator
- EVTReview RejectedNot shown → Review rejected
- SVCRating AggregatorWrite aggregate
- DBRating CacheVisible on storefront
- ACTORReview is live
- ACTORReview rejected
Overview
Review Submission documents the journey of a customer review from submission through moderation to publication. A review is only ever folded into a product's rating once it has been approved.
How it works
- A customer submits a review via the Review API, which stores it in the Review Database and publishes Review Submitted.
- The Review Moderation Worker screens the review and publishes either Review Published or Review Rejected.
- On approval, the Rating Aggregator updates the product's aggregate rating in the Rating Cache and the review goes live.
Entities
The domain model behind the messages.
Authentication Session
v1.0.0A successful customer authentication session.
sessionIdUUIDRequiredUnique authentication session identifier.
accountIdUUID → customer-accountRequiredAccount authenticated in the session.
authenticatedAtdatetimeRequiredTime authentication succeeded.
expiresAtdatetimeRequiredTime the session expires.
Overview
Authentication Session represents successful login behavior emitted by Customer Authenticated.
/** A successful customer authentication session. */
export interface AuthenticationSession {
/** Unique authentication session identifier. */
sessionId: unknown;
/** Account authenticated in the session. */
accountId: unknown;
/** Time authentication succeeded. */
authenticatedAt: unknown;
/** Time the session expires. */
expiresAt: unknown;
}Cart
Aggregate Rootv1.0.0The customer's active collection of items before an order exists.
cartIdUUIDRequiredUnique cart identifier.
customerIdUUID → customer-profileCustomer that owns the cart, if authenticated.
statusstringRequiredCurrent cart state.
activechecked-outabandonedupdatedAtdatetimeRequiredTime the cart last changed.
Overview
Cart is the Shopping domain aggregate. It accepts item changes and emits Cart Checked Out when the customer commits to buy.
/** The customer's active collection of items before an order exists. */
export interface Cart {
/** Unique cart identifier. */
cartId: unknown;
/** Customer that owns the cart, if authenticated. */
customerId?: unknown;
/** Current cart state. */
status: "active" | "checked-out" | "abandoned";
/** Time the cart last changed. */
updatedAt: unknown;
}Cart Item
v1.0.0A product variant and quantity inside a cart.
cartItemIdUUIDRequiredUnique cart item identifier.
cartIdUUID → cartRequiredCart this item belongs to.
productIdUUID → productRequiredProduct selected by the customer.
quantityintegerRequiredQuantity requested.
Overview
Cart Item records the customer's intent to buy a product variant before checkout. It is owned by Cart.
/** A product variant and quantity inside a cart. */
export interface CartItem {
/** Unique cart item identifier. */
cartItemId: unknown;
/** Cart this item belongs to. */
cartId: unknown;
/** Product selected by the customer. */
productId: unknown;
/** Quantity requested. */
quantity: number;
}Category
Aggregate Rootv1.0.0A merchandising grouping used to organize products for discovery.
categoryIdUUIDRequiredUnique category identifier.
slugstringRequiredStable URL-safe category key.
displayNamestringRequiredCustomer-facing category name.
parentCategoryIdUUID → categoryParent category for hierarchy navigation.
Overview
Category defines how products are grouped for browsing. It is owned by the Catalog domain and projected into the Search System for discovery.
/** A merchandising grouping used to organize products for discovery. */
export interface Category {
/** Unique category identifier. */
categoryId: unknown;
/** Stable URL-safe category key. */
slug: string;
/** Customer-facing category name. */
displayName: string;
/** Parent category for hierarchy navigation. */
parentCategoryId?: unknown;
}Checkout Session
Aggregate Rootv1.0.0The orchestration state for turning a checked-out cart into an order.
checkoutSessionIdUUIDRequiredUnique checkout session identifier.
cartIdUUID → cartRequiredCart being checked out.
statusstringRequiredCurrent checkout state.
startedAtdatetimeRequiredTime checkout orchestration started.
Overview
Checkout Session tracks the saga managed by Checkout Orchestrator across inventory reservation, payment authorization and order creation.
/** The orchestration state for turning a checked-out cart into an order. */
export interface CheckoutSession {
/** Unique checkout session identifier. */
checkoutSessionId: unknown;
/** Cart being checked out. */
cartId: unknown;
/** Current checkout state. */
status: string;
/** Time checkout orchestration started. */
startedAt: unknown;
}Customer Account
Aggregate Rootv1.0.0The identity account used to authenticate a customer.
accountIdUUIDRequiredUnique account identifier.
customerIdUUID → customer-profileRequiredCustomer profile linked to this account.
providerstringRequiredIdentity provider name.
statusstringRequiredAccount lifecycle state.
Overview
Customer Account belongs to the Identity Provider boundary and should not be queried directly by order, payment or review services.
/** The identity account used to authenticate a customer. */
export interface CustomerAccount {
/** Unique account identifier. */
accountId: unknown;
/** Customer profile linked to this account. */
customerId: unknown;
/** Identity provider name. */
provider: string;
/** Account lifecycle state. */
status: string;
}Customer Address
v1.0.0A saved address attached to a customer profile.
addressIdUUIDRequiredUnique address identifier.
customerIdUUID → customer-profileRequiredCustomer who owns the address.
countryCodestringRequiredISO country code.
postalCodestringRequiredPostal or ZIP code.
Overview
Customer Address supports checkout and fulfilment while remaining owned by the Customer domain.
/** A saved address attached to a customer profile. */
export interface CustomerAddress {
/** Unique address identifier. */
addressId: unknown;
/** Customer who owns the address. */
customerId: unknown;
/** ISO country code. */
countryCode: string;
/** Postal or ZIP code. */
postalCode: string;
}Customer Profile
Aggregate Rootv1.0.0The customer details Acme uses for commerce interactions.
customerIdUUIDRequiredUnique customer identifier.
emailstringRequiredCustomer email address.
displayNamestringPreferred customer display name.
statusstringRequiredCustomer profile state.
Overview
Customer Profile is owned by Customer Management System and is separate from authentication credentials.
/** The customer details Acme uses for commerce interactions. */
export interface CustomerProfile {
/** Unique customer identifier. */
customerId: unknown;
/** Customer email address. */
email: string;
/** Preferred customer display name. */
displayName?: string;
/** Customer profile state. */
status: string;
}Discount
v1.0.0The calculated benefit applied to a cart or cart item.
discountIdUUIDRequiredUnique discount identifier.
promotionIdUUID → promotionPromotion that produced the discount.
amountdecimalRequiredMonetary value of the discount.
reasonstringRequiredHuman-readable explanation for the discount.
Overview
Discount is a calculated result from Calculate Discount. It is separate from cart persistence so promotion logic can evolve independently.
/** The calculated benefit applied to a cart or cart item. */
export interface Discount {
/** Unique discount identifier. */
discountId: unknown;
/** Promotion that produced the discount. */
promotionId?: unknown;
/** Monetary value of the discount. */
amount: unknown;
/** Human-readable explanation for the discount. */
reason: string;
}Fraud Check
v1.0.0Fraud screening result associated with a payment attempt.
fraudCheckIdUUIDRequiredUnique fraud check identifier.
paymentIdUUID → paymentRequiredPayment attempt being screened.
resultstringRequiredScreening result.
passedfailedreviewcheckedAtdatetimeRequiredTime screening completed.
Overview
Fraud Check documents the screening outcome from Fraud Detection so payment decisions are auditable.
/** Fraud screening result associated with a payment attempt. */
export interface FraudCheck {
/** Unique fraud check identifier. */
fraudCheckId: unknown;
/** Payment attempt being screened. */
paymentId: unknown;
/** Screening result. */
result: "passed" | "failed" | "review";
/** Time screening completed. */
checkedAt: unknown;
}Inventory Reservation
Aggregate Rootv1.0.0Stock held for a checkout or order before fulfilment.
reservationIdUUIDRequiredUnique reservation identifier.
orderIdUUID → orderOrder associated with the reservation once created.
productIdUUID → productRequiredProduct being reserved.
expiresAtdatetimeRequiredTime the reservation expires if not committed.
Overview
Inventory Reservation is created during checkout by Reserve Inventory and released if the saga fails.
/** Stock held for a checkout or order before fulfilment. */
export interface InventoryReservation {
/** Unique reservation identifier. */
reservationId: unknown;
/** Order associated with the reservation once created. */
orderId?: unknown;
/** Product being reserved. */
productId: unknown;
/** Time the reservation expires if not committed. */
expiresAt: unknown;
}Moderation Decision
v1.0.0The outcome of reviewing submitted customer feedback.
moderationDecisionIdUUIDRequiredUnique moderation decision identifier.
reviewIdUUID → reviewRequiredReview being moderated.
outcomestringRequiredModeration result.
publishedrejecteddecidedAtdatetimeRequiredTime the decision was made.
Overview
Moderation Decision records why a review became published or rejected and supports audit of Review Moderation Worker behavior.
/** The outcome of reviewing submitted customer feedback. */
export interface ModerationDecision {
/** Unique moderation decision identifier. */
moderationDecisionId: unknown;
/** Review being moderated. */
reviewId: unknown;
/** Moderation result. */
outcome: "published" | "rejected";
/** Time the decision was made. */
decidedAt: unknown;
}Order
Aggregate Rootv1.0.0The durable customer order created after successful checkout.
orderIdUUIDRequiredUnique order identifier.
customerCustomer → customer-profileRequiredCustomer who placed the order.
statusstringRequiredCurrent order lifecycle state.
totalAmountdecimalRequiredTotal order value at creation.
deliveryAddressobjectRequiredDelivery address captured when the order was placed.
line1stringRequiredFirst line of the delivery address.
citystringRequiredDelivery city.
postalCodestringRequiredDelivery postal code.
countryCodestringRequiredISO 3166-1 alpha-2 delivery country code.
adjustmentsarray of objectDiscounts and credits captured as part of this order.
descriptionstringRequiredReason for the adjustment.
amountdecimalRequiredSigned amount applied to the order total.
Overview
Order is the main aggregate in Order Management System. It emits order lifecycle events used by Fulfilment and support workflows.
/** The durable customer order created after successful checkout. */
export interface Order {
/** Unique order identifier. */
orderId: unknown;
/** Customer who placed the order. */
customer: unknown;
/** Current order lifecycle state. */
status: string;
/** Total order value at creation. */
totalAmount: unknown;
/** Delivery address captured when the order was placed. */
deliveryAddress: {
/** First line of the delivery address. */
line1: string;
/** Delivery city. */
city: string;
/** Delivery postal code. */
postalCode: string;
/** ISO 3166-1 alpha-2 delivery country code. */
countryCode: string;
};
/** Discounts and credits captured as part of this order. */
adjustments?: {
/** Reason for the adjustment. */
description: string;
/** Signed amount applied to the order total. */
amount: unknown;
}[];
}Order Line
v1.0.0A purchased product and quantity within an order.
orderLineIdUUIDRequiredUnique order line identifier.
orderIdUUID → orderRequiredOrder this line belongs to.
productIdUUID → productRequiredProduct purchased.
quantityintegerRequiredQuantity purchased.
Overview
Order Line snapshots the products bought at checkout. It should not replace the Catalog domain's authoritative product data.
/** A purchased product and quantity within an order. */
export interface OrderLine {
/** Unique order line identifier. */
orderLineId: unknown;
/** Order this line belongs to. */
orderId: unknown;
/** Product purchased. */
productId: unknown;
/** Quantity purchased. */
quantity: number;
}Order Status History
v1.0.0Audit history of order lifecycle state changes.
orderStatusHistoryIdUUIDRequiredUnique status history record.
orderIdUUID → orderRequiredOrder whose status changed.
statusstringRequiredNew order status.
changedAtdatetimeRequiredTime the status changed.
Overview
Order Status History provides an audit trail for customer support, fulfilment exceptions and order lifecycle debugging.
/** Audit history of order lifecycle state changes. */
export interface OrderStatusHistory {
/** Unique status history record. */
orderStatusHistoryId: unknown;
/** Order whose status changed. */
orderId: unknown;
/** New order status. */
status: string;
/** Time the status changed. */
changedAt: unknown;
}Payment
Aggregate Rootv1.0.0Acme's internal record of payment intent and outcome for an order.
paymentIdUUIDRequiredUnique payment identifier.
orderIdUUID → orderRequiredOrder being paid for.
amountdecimalRequiredAmount requested.
statusstringRequiredPayment lifecycle status.
Overview
Payment is the Payments domain aggregate. It records Acme's view of payment state regardless of external provider retries or webhook order.
/** Acme's internal record of payment intent and outcome for an order. */
export interface Payment {
/** Unique payment identifier. */
paymentId: unknown;
/** Order being paid for. */
orderId: unknown;
/** Amount requested. */
amount: unknown;
/** Payment lifecycle status. */
status: string;
}Payment Authorization
v1.0.0Approval from a payment provider to reserve funds for an order.
authorizationIdUUIDRequiredUnique authorization identifier.
paymentIdUUID → paymentRequiredPayment this authorization belongs to.
providerReferencestringRequiredExternal payment provider reference.
authorizedAtdatetimeRequiredTime authorization was granted.
Overview
Payment Authorization captures the result of Authorize Payment and links Acme payment state to provider state.
/** Approval from a payment provider to reserve funds for an order. */
export interface PaymentAuthorization {
/** Unique authorization identifier. */
authorizationId: unknown;
/** Payment this authorization belongs to. */
paymentId: unknown;
/** External payment provider reference. */
providerReference: string;
/** Time authorization was granted. */
authorizedAt: unknown;
}Product
Aggregate Rootv1.0.0The sellable item Acme manages in the product catalog.
productIdUUIDRequiredUnique product identifier.
skustringRequiredPrimary merchandising SKU.
namestringRequiredCustomer-facing product name.
statusstringRequiredProduct publication state.
draftactivearchivedOverview
The Product is the Catalog domain's core aggregate. It is created and maintained by Product API and published to downstream consumers through product events.
/** The sellable item Acme manages in the product catalog. */
export interface Product {
/** Unique product identifier. */
productId: unknown;
/** Primary merchandising SKU. */
sku: string;
/** Customer-facing product name. */
name: string;
/** Product publication state. */
status: "draft" | "active" | "archived";
}Product Variant
v1.0.0A purchasable variation of a product, such as size or color.
variantIdUUIDRequiredUnique variant identifier.
productIdUUID → productRequiredProduct this variant belongs to.
skustringRequiredVariant-level SKU.
attributesobjectRequiredVariant dimensions such as size, color or material.
Overview
Product Variant captures the concrete option a customer can buy. It belongs to a Product and is indexed into search when product data changes.
/** A purchasable variation of a product, such as size or color. */
export interface ProductVariant {
/** Unique variant identifier. */
variantId: unknown;
/** Product this variant belongs to. */
productId: unknown;
/** Variant-level SKU. */
sku: string;
/** Variant dimensions such as size, color or material. */
attributes: unknown;
}Promotion
Aggregate Rootv1.0.0A commercial offer evaluated against a cart.
promotionIdUUIDRequiredUnique promotion identifier.
codestringOptional customer-entered promotion code.
categoryIdUUID → categoryCategory the promotion applies to when scoped.
statusstringRequiredPromotion lifecycle state.
startsAtdatetimeRequiredWhen the promotion becomes active.
Overview
Promotion is owned by the Promotion System and is evaluated when Shopping calculates discounts for a cart.
/** A commercial offer evaluated against a cart. */
export interface Promotion {
/** Unique promotion identifier. */
promotionId: unknown;
/** Optional customer-entered promotion code. */
code?: string;
/** Category the promotion applies to when scoped. */
categoryId?: unknown;
/** Promotion lifecycle state. */
status: string;
/** When the promotion becomes active. */
startsAt: unknown;
}Rating Summary
v1.0.0Aggregated review statistics for a product.
productIdUUID → productRequiredProduct being summarized.
averageRatingdecimalRequiredAverage published rating.
reviewCountintegerRequiredNumber of published reviews.
updatedAtdatetimeRequiredTime the summary was recalculated.
Overview
Rating Summary is the read model maintained by Rating Aggregator and stored in Rating Cache.
/** Aggregated review statistics for a product. */
export interface RatingSummary {
/** Product being summarized. */
productId: unknown;
/** Average published rating. */
averageRating: unknown;
/** Number of published reviews. */
reviewCount: number;
/** Time the summary was recalculated. */
updatedAt: unknown;
}Refund
Aggregate Rootv1.0.0A request to return money to a customer after payment.
refundIdUUIDRequiredUnique refund identifier.
paymentIdUUID → paymentRequiredPayment being refunded.
amountdecimalRequiredRefund amount.
statusstringRequiredRefund lifecycle state.
Overview
Refund is owned by Payments and records refund requests and provider outcomes such as Refund Processed.
/** A request to return money to a customer after payment. */
export interface Refund {
/** Unique refund identifier. */
refundId: unknown;
/** Payment being refunded. */
paymentId: unknown;
/** Refund amount. */
amount: unknown;
/** Refund lifecycle state. */
status: string;
}Review
Aggregate Rootv1.0.0A customer's review and rating of a product, including its moderation lifecycle.
reviewIdUUIDRequiredUnique identifier for the review.
productIdstring → productRequiredThe product being reviewed.
customerIdstring → customer-profileRequiredThe customer who wrote the review.
ratingintegerRequiredStar rating from 1 to 5.
titlestringShort headline for the review.
bodystringRequiredThe review text.
statusstringRequiredLifecycle status of the review.
submittedpublishedrejectedsubmittedAtdatetimeRequiredWhen the review was submitted.
Overview
The Review is the core aggregate of the Reviews & Ratings domain. It captures a customer's rating and written feedback for a product, along with the moderation status that controls whether it is visible on the storefront.
A review moves through three states:
- submitted — stored by the Review API, awaiting moderation.
- published — passed moderation and visible (the Rating Aggregator folds it into the product's rating).
- rejected — failed moderation and never shown, but kept for audit.
/** A customer's review and rating of a product, including its moderation lifecycle. */
export interface Review {
/** Unique identifier for the review. */
reviewId: unknown;
/** The product being reviewed. */
productId: unknown;
/** The customer who wrote the review. */
customerId: unknown;
/** Star rating from 1 to 5. */
rating: number;
/** Short headline for the review. */
title?: string;
/** The review text. */
body: string;
/** Lifecycle status of the review. */
status: "submitted" | "published" | "rejected";
/** When the review was submitted. */
submittedAt: unknown;
}Review Flag
v1.0.0A customer report that a review may violate policy.
flagIdUUIDRequiredUnique review flag identifier.
reviewIdUUID → reviewRequiredReview being reported.
reasonstringRequiredReason selected by the customer.
flaggedAtdatetimeRequiredTime the review was flagged.
Overview
Review Flag captures Flag Review interactions and can send a published review back through moderation.
/** A customer report that a review may violate policy. */
export interface ReviewFlag {
/** Unique review flag identifier. */
flagId: unknown;
/** Review being reported. */
reviewId: unknown;
/** Reason selected by the customer. */
reason: string;
/** Time the review was flagged. */
flaggedAt: unknown;
}Review Vote
v1.0.0A customer's helpfulness vote on a product review.
voteIdUUIDRequiredUnique review vote identifier.
reviewIdUUID → reviewRequiredReview being voted on.
customerIdUUID → customer-profileRequiredCustomer who voted.
votedAtdatetimeRequiredTime the vote was submitted.
Overview
Review Vote captures Vote Review Helpful interactions and contributes to review helpfulness ranking.
/** A customer's helpfulness vote on a product review. */
export interface ReviewVote {
/** Unique review vote identifier. */
voteId: unknown;
/** Review being voted on. */
reviewId: unknown;
/** Customer who voted. */
customerId: unknown;
/** Time the vote was submitted. */
votedAt: unknown;
}Search Document
v1.0.0The denormalized representation of product data indexed by Search.
documentIdstringRequiredSearch index document identifier.
productIdUUID → productRequiredProduct represented by the document.
searchableTextstringRequiredText used for matching and ranking.
indexedAtdatetimeRequiredTime the document was last indexed.
Overview
Search Document is the read model maintained by Search System. It is eventually consistent with the Product Catalog System.
/** The denormalized representation of product data indexed by Search. */
export interface SearchDocument {
/** Search index document identifier. */
documentId: string;
/** Product represented by the document. */
productId: unknown;
/** Text used for matching and ranking. */
searchableText: string;
/** Time the document was last indexed. */
indexedAt: unknown;
}Shipment
Aggregate Rootv1.0.0A carrier delivery for a packed customer order.
shipmentIdUUIDRequiredUnique shipment identifier.
orderIdUUID → orderRequiredOrder being shipped.
carrierReferencestringExternal carrier tracking reference.
statusstringRequiredShipment delivery status.
Overview
Shipment is created by the Shipping System and updated from carrier events such as Shipment Created and Shipment Delivered.
/** A carrier delivery for a packed customer order. */
export interface Shipment {
/** Unique shipment identifier. */
shipmentId: unknown;
/** Order being shipped. */
orderId: unknown;
/** External carrier tracking reference. */
carrierReference?: string;
/** Shipment delivery status. */
status: string;
}Stock Item
Aggregate Rootv1.0.0The inventory record for a product variant at a location.
stockItemIdUUIDRequiredUnique stock item identifier.
productIdUUID → productRequiredProduct held in stock.
locationIdstringRequiredWarehouse or fulfilment location.
availableQuantityintegerRequiredQuantity available to reserve.
Overview
Stock Item is the Inventory System's view of available stock for a product at a fulfilment location.
/** The inventory record for a product variant at a location. */
export interface StockItem {
/** Unique stock item identifier. */
stockItemId: unknown;
/** Product held in stock. */
productId: unknown;
/** Warehouse or fulfilment location. */
locationId: string;
/** Quantity available to reserve. */
availableQuantity: number;
}Warehouse Pick
v1.0.0A warehouse task to pick items for a completed order.
pickIdUUIDRequiredUnique warehouse pick identifier.
orderIdUUID → orderRequiredOrder being picked.
assignedTostringWarehouse worker or automation lane assigned.
statusstringRequiredPick task status.
Overview
Warehouse Pick represents the operational task handled by the Warehouse System before an order can be packed and shipped.
/** A warehouse task to pick items for a completed order. */
export interface WarehousePick {
/** Unique warehouse pick identifier. */
pickId: unknown;
/** Order being picked. */
orderId: unknown;
/** Warehouse worker or automation lane assigned. */
assignedTo?: string;
/** Pick task status. */
status: string;
}Teams
Who owns what, and how to reach them.
Customer Platform
Owns the Customer domain — customer profiles and authentication across Acme Inc.
Fulfilment Platform
Owns the Fulfilment domain — reserving stock, picking and packing orders, and shipping them to customers.
Ordering Platform
Owns the Ordering domain — turning a checked-out cart into a confirmed order.
Payments Platform
Owns the Payments domain — authorizing payments, processing refunds, and integrating with external payment and fraud providers.
Product Platform
Owns the Product Catalog System — the source of truth for product data at Acme Inc.
Reviews Platform
Owns the Reviews & Ratings domain — how customers review products and how those reviews are moderated, published and aggregated into ratings.
Search Platform
Owns the Search System — keeps the catalog discoverable through fast, relevant product search.
Shopping Platform
Owns the Shopping domain — the cart and the promotions applied to it.
People
Individual owners in the catalog.
David Boyne
Lead developer
Nothing in the catalog lists them as an owner.