Skip to main content
npayload is launching soon.
npayloadDocs
Solutions

npayload for Ecommerce

Order events, inventory sync, fulfillment webhooks, and transactional consistency

The challenge

Ecommerce systems are event-driven by nature. An order placement triggers a cascade of downstream actions: charge the customer, reserve inventory, notify the warehouse, send a confirmation email, update analytics. Each of these services has different reliability characteristics, different SLAs, and different failure modes.

When one service goes down, the entire order pipeline can stall. When events arrive out of order, inventory counts drift. When a payment event is processed twice, a customer gets double-charged. Building the infrastructure to handle all of this reliably is a massive undertaking.

How npayload solves it

Order lifecycle events

Model the full order lifecycle as a series of events flowing through dedicated channels. Each stage (created, paid, shipped, delivered) is a distinct event type that downstream services can subscribe to independently.

Order lifecycle
import { NPayload } from "@npayload/node";

const np = new NPayload({ apiKey: process.env.NPAYLOAD_API_KEY });

// Publish order created event
await np.messages.publish({
  channelId: "orders.lifecycle",
  type: "order.created",
  groupKey: orderId, // FIFO per order
  payload: {
    orderId,
    customerId: "cus_abc",
    items: [
      { sku: "WIDGET-001", quantity: 2, price: 2499 },
      { sku: "GADGET-042", quantity: 1, price: 7999 },
    ],
    total: 12997,
    currency: "usd",
  },
});

Transactional publish for atomic operations

When a payment is confirmed, you need to update inventory, trigger fulfillment, and send a notification. With transactional publish, either all of these events are published or none of them are. No partial state.

Atomic order fulfillment
await np.messages.publishTransactional([
  {
    channelId: "inventory.updates",
    type: "inventory.reserved",
    payload: {
      items: [
        { sku: "WIDGET-001", quantity: -2 },
        { sku: "GADGET-042", quantity: -1 },
      ],
    },
  },
  {
    channelId: "fulfillment.orders",
    type: "fulfillment.requested",
    payload: {
      orderId,
      warehouseId: "wh-east-1",
      items: order.items,
      shippingAddress: order.shippingAddress,
    },
  },
  {
    channelId: "notifications.email",
    type: "email.order-confirmed",
    payload: {
      customerId: order.customerId,
      orderId,
      estimatedDelivery: "2026-03-12",
    },
  },
  {
    channelId: "analytics.events",
    type: "purchase.completed",
    payload: {
      orderId,
      total: order.total,
      itemCount: order.items.length,
    },
  },
]);

Fan-out to multiple services

A single order event can fan out to fulfillment, billing, analytics, and notification services simultaneously. Each subscriber processes the event independently with its own retry policy and circuit breaker.

Multi-service fan-out
// Subscribe multiple services to the same channel
await np.subscriptions.create({
  channelId: "orders.lifecycle",
  endpoint: "https://fulfillment.internal/webhooks/orders",
  name: "fulfillment-service",
});

await np.subscriptions.create({
  channelId: "orders.lifecycle",
  endpoint: "https://billing.internal/webhooks/orders",
  name: "billing-service",
});

await np.subscriptions.create({
  channelId: "orders.lifecycle",
  endpoint: "https://analytics.internal/webhooks/orders",
  name: "analytics-service",
});

await np.subscriptions.create({
  channelId: "orders.lifecycle",
  endpoint: "https://notifications.internal/webhooks/orders",
  name: "notification-service",
});

Message groups for per-order FIFO

When multiple events for the same order are in flight (created, paid, shipped), they must be processed in order. Message groups guarantee FIFO ordering per order while allowing events for different orders to process in parallel.

Per-order FIFO ordering
// All events with the same groupKey are delivered in order
await np.messages.publish({
  channelId: "orders.lifecycle",
  type: "order.paid",
  groupKey: orderId, // Same groupKey = same FIFO group
  payload: { orderId, paidAt: new Date().toISOString() },
});

await np.messages.publish({
  channelId: "orders.lifecycle",
  type: "order.shipped",
  groupKey: orderId,
  payload: { orderId, trackingNumber: "1Z999AA10123456784" },
});

Connectors for bridging existing systems

Already running Kafka for warehouse systems or SQS for legacy services? npayload connectors bridge events between your npayload channels and existing infrastructure without code changes.

Bridge to existing Kafka cluster
await np.connectors.create({
  channelId: "inventory.updates",
  type: "kafka",
  config: {
    brokers: ["kafka-1.warehouse.internal:9092"],
    topic: "inventory-events",
    groupId: "npayload-bridge",
  },
});

Priority queues for critical events

Not all events are equal. Payment failures and fraud alerts should jump the queue ahead of analytics events. Priority queues let you assign importance levels so critical events are processed first.

Priority-based processing
// Fraud alert: highest priority
await np.messages.publish({
  channelId: "orders.alerts",
  type: "fraud.suspected",
  priority: 1, // 1 = highest priority
  payload: {
    orderId,
    riskScore: 0.95,
    signals: ["velocity", "geo-mismatch", "new-device"],
  },
});

// Routine analytics: lower priority
await np.messages.publish({
  channelId: "orders.alerts",
  type: "analytics.daily-summary",
  priority: 5,
  payload: { date: "2026-03-07", orderCount: 1523 },
});

Example: order processing saga

Feature summary

FeatureWhat it does for ecommerce
Transactional publishAtomic order, inventory, and notification events. No partial state.
Message groupsPer-order FIFO ordering. Events for the same order always arrive in sequence.
Fan-outOne order event reaches fulfillment, billing, analytics, and notifications independently.
Priority queuesFraud alerts and payment failures processed before routine analytics.
Dead letter queuesFailed deliveries are preserved. No order event is silently lost.
ConnectorsBridge to Kafka, SQS, Azure Event Hubs, and GCP Pub/Sub without code changes.
Circuit breakersA failing fulfillment service does not block billing or notifications.
Idempotency keysPrevent duplicate charges from retry storms.
Event catalogueDocument every order event type with schemas for downstream teams.

Next steps

Was this page helpful?

On this page