Integration Event in Microservices
1. What is an Integration Event?
An Integration Event is a message published by one microservice to inform other microservices or external systems that an important business event has occurred.
Integration Event = an event used to communicate across service boundaries.
For example, after the Order Service successfully creates an order, it may publish:
OrderCreatedIntegrationEvent
Other services can react:
Order Service
│
│ OrderCreatedIntegrationEvent
▼
Message Broker
│
┌───────────┼───────────┐
▼ ▼ ▼
Inventory Notification Analytics
Service Service Service
The Order Service doesn't directly call every interested service.
2. Simple Example
Suppose we have:
Order Service
Payment Service
Inventory Service
Notification Service
A customer creates an order.
Inside Order Service:
Create Order
↓
Save Order
↓
Order successfully created
Order Service then publishes:
OrderCreatedIntegrationEvent
Other microservices consume it:
Order Service
│
│ OrderCreatedIntegrationEvent
▼
Message Broker
│
├──> Inventory Service
├──> Notification Service
└──> Analytics Service
Each service reacts independently.
3. Why Do We Need Integration Events?
Without integration events, Order Service might directly call other services:
Order Service
│
├──HTTP──> Inventory Service
├──HTTP──> Notification Service
└──HTTP──> Analytics Service
This creates direct runtime dependencies.
If we later add:
Loyalty Service
Order Service may also need another call:
Order Service
├──> Inventory
├──> Notification
├──> Analytics
└──> Loyalty
The Order Service becomes increasingly aware of downstream systems.
With an Integration Event:
Order Service
│
│ OrderCreatedIntegrationEvent
▼
Message Broker
│
├──> Inventory
├──> Notification
├──> Analytics
└──> Loyalty
The publisher doesn't need to know every subscriber.
This provides loose coupling.
4. Purpose of an Integration Event
Integration Events are mainly used to:
- Communicate between microservices
- Notify other bounded contexts
- Support asynchronous communication
- Reduce direct service-to-service coupling
- Implement Event-Driven Architecture
- Propagate important business changes
- Allow multiple services to react independently
- Support eventual consistency
5. Integration Event vs Normal Event
The word event is broad.
For example:
Something happened
An Integration Event specifically means:
Something happened in one service that other services need to know about.
Example:
OrderCreated
If it only matters inside Order Service, it may remain an internal/domain event.
If other services need it:
Inventory
Notification
Analytics
we can expose an appropriate Integration Event.
6. Domain Event vs Integration Event
This is the most important distinction.
Domain Event
A Domain Event represents something important that happened inside a domain/bounded context.
Example:
OrderCreatedDomainEvent
It may be used internally by Order Service:
Order Service
│
├── Domain
├── Application
└── Internal handlers
It is primarily an internal domain concept.
Integration Event
An Integration Event crosses the microservice boundary.
Order Service
│
│ Integration Event
▼
Message Broker
│
▼
Other Microservices
Example:
OrderCreatedIntegrationEvent
7. Domain Event vs Integration Event Comparison
| Domain Event | Integration Event |
|---|---|
| Internal to a bounded context | Crosses service boundaries |
| Represents domain occurrence | Represents information exposed to other systems |
| Usually handled internally | Consumed by other services |
| May run in-process | Usually transported externally |
| Doesn't require a broker | Commonly published through a broker |
| Can contain domain-specific details | Should expose a stable integration contract |
| Internal implementation concern | Public service contract |
OrderCreatedDomainEvent |
OrderCreatedIntegrationEvent |
8. Example Flow
Suppose:
Order Service
receives:
POST /api/orders
Step 1 — Command
CreateOrder
Step 2 — Domain Logic
Order.Create()
Step 3 — Domain Event
OrderCreatedDomainEvent
This represents an internal domain fact.
Step 4 — Save Database Changes
Orders Database
Step 5 — Integration Event
An externally consumable event is prepared:
OrderCreatedIntegrationEvent
Step 6 — Publish
Order Service
↓
Message Broker
Step 7 — Other Services React
OrderCreatedIntegrationEvent
│
├──> Inventory Service
├──> Notification Service
└──> Analytics Service
9. Complete Architecture
Client
│
│ CreateOrder
▼
┌────────────────────┐
│ Order Service │
│ │
│ Domain │
│ │ │
│ ▼ │
│ OrderCreated │
│ DomainEvent │
│ │ │
│ ▼ │
│ Application Layer │
│ │ │
│ ▼ │
│ OrderCreated │
│ IntegrationEvent │
└─────────┬──────────┘
│
▼
Message Broker
│
┌─────┼──────────┐
▼ ▼ ▼
Inventory Email Analytics
Service Service Service
10. Integration Event Example in C#
A simple base class:
public abstract record IntegrationEvent
{
public Guid EventId { get; init; } = Guid.NewGuid();
public DateTime OccurredAtUtc { get; init; }
= DateTime.UtcNow;
}
Then:
public record OrderCreatedIntegrationEvent(
int OrderId,
int CustomerId,
decimal TotalAmount
) : IntegrationEvent;
Example object:
var integrationEvent =
new OrderCreatedIntegrationEvent(
OrderId: 1001,
CustomerId: 501,
TotalAmount: 2500);
11. What Should an Integration Event Contain?
It should contain enough information for subscribers to understand the event.
For example:
public record OrderCreatedIntegrationEvent(
int OrderId,
int CustomerId,
decimal TotalAmount,
DateTime CreatedAt
) : IntegrationEvent;
Serialized message:
{
"eventId": "5d05b89d-7931-4d0f-87e4-5367352b9690",
"eventType": "OrderCreated",
"orderId": 1001,
"customerId": 501,
"totalAmount": 2500,
"createdAt": "2026-09-29T10:30:00Z"
}
12. Don't Expose Your Domain Entity Directly
This is important.
Suppose your Domain contains:
public class Order
{
public int Id { get; set; }
public Customer Customer { get; set; }
public List<OrderItem> Items { get; set; }
public Payment Payment { get; set; }
public InternalStatus InternalStatus { get; set; }
// Many internal properties
}
Don't simply publish:
await eventBus.PublishAsync(order);
That exposes your internal domain model.
Instead create a dedicated contract:
public record OrderCreatedIntegrationEvent(
int OrderId,
int CustomerId,
decimal TotalAmount
);
This keeps:
Internal Domain Model
≠
External Integration Contract
That separation is important in microservices.
13. Why Separate Domain Event and Integration Event?
Suppose your internal domain event is:
public class OrderCreatedDomainEvent
{
public Order Order { get; }
}
It contains the complete Domain object.
Publishing that externally would tightly couple other services to:
Order entity
Navigation properties
Internal enums
Internal business structures
Domain changes
Instead, translate it:
OrderCreatedDomainEvent
↓
Map/Transform
↓
OrderCreatedIntegrationEvent
The Integration Event contains only the external contract.
14. Integration Event Publisher
We can define:
public interface IIntegrationEventPublisher
{
Task PublishAsync<T>(
T integrationEvent,
CancellationToken cancellationToken = default)
where T : IntegrationEvent;
}
The implementation could use:
Azure Service Bus
RabbitMQ
Kafka
The Application layer doesn't necessarily need to know which broker is being used.
15. Azure Service Bus Example
Required NuGet package:
dotnet add package Azure.Messaging.ServiceBus
Publisher:
using Azure.Messaging.ServiceBus;
using System.Text.Json;
public class AzureServiceBusEventPublisher
: IIntegrationEventPublisher
{
private readonly ServiceBusSender _sender;
public AzureServiceBusEventPublisher(
ServiceBusClient client)
{
_sender =
client.CreateSender("orders-topic");
}
public async Task PublishAsync<T>(
T integrationEvent,
CancellationToken cancellationToken = default)
where T : IntegrationEvent
{
string json =
JsonSerializer.Serialize(integrationEvent);
var message =
new ServiceBusMessage(json)
{
MessageId =
integrationEvent.EventId.ToString(),
Subject =
typeof(T).Name
};
await _sender.SendMessageAsync(
message,
cancellationToken);
}
}
16. Publishing the Integration Event
After an order is successfully created:
var integrationEvent =
new OrderCreatedIntegrationEvent(
order.Id,
order.CustomerId,
order.TotalAmount);
await _eventPublisher.PublishAsync(
integrationEvent);
Flow:
Order Created
↓
OrderCreatedIntegrationEvent
↓
IIntegrationEventPublisher
↓
Azure Service Bus
↓
orders-topic
17. Consumer Example
Notification Service subscribes to the event.
orders-topic
↓
notification-subscription
↓
Notification Service
Example:
ServiceBusProcessor processor =
client.CreateProcessor(
"orders-topic",
"notification-subscription");
processor.ProcessMessageAsync += async args =>
{
string json =
args.Message.Body.ToString();
var orderCreated =
JsonSerializer.Deserialize<
OrderCreatedIntegrationEvent>(json);
if (orderCreated is not null)
{
Console.WriteLine(
$"Send confirmation for Order {orderCreated.OrderId}");
}
await args.CompleteMessageAsync(
args.Message);
};
Another service can consume the same event independently:
orders-topic
│
├── notification-subscription
│ ↓
│ Notification Service
│
├── inventory-subscription
│ ↓
│ Inventory Service
│
└── analytics-subscription
↓
Analytics Service
18. Integration Event and Pub/Sub
Integration Events are commonly distributed using Publish/Subscribe.
Publisher
↓
Integration Event
↓
Topic
│
├──> Subscriber A
├──> Subscriber B
└──> Subscriber C
Example:
Order Service
↓
OrderCreatedIntegrationEvent
↓
Orders Topic
│
├──> Inventory
├──> Notification
└──> Analytics
This is one of the core patterns in Event-Driven Microservices.
19. Integration Event vs Command
Another important interview distinction:
Command
ProcessPayment
means:
Please perform this action.
Integration Event
PaymentCompleted
means:
This already happened; other systems may react.
Comparison:
| Command | Integration Event |
|---|---|
| Request | Fact |
ProcessPayment |
PaymentCompleted |
| Usually one logical handler | Zero, one, or many subscribers |
| Often Queue | Often Topic/Pub-Sub |
| Sender expects action | Publisher announces occurrence |
20. Integration Event and Eventual Consistency
Suppose Order Service creates:
Order 1001
At time T1:
Order Database
Order = Created
Inventory Service may not have processed the event yet.
At T2:
Inventory Service
↓
OrderCreatedIntegrationEvent
↓
Reserve inventory
Therefore, different services may temporarily have different views of the overall business state.
This is eventual consistency.
T1
Order Service → Updated
Inventory Service → Not yet updated
T2
Order Service → Updated
Inventory Service → Updated
This is normal in many asynchronous microservice architectures.
21. The Database + Publish Problem
This is one of the most important production issues.
Consider:
await orderRepository.AddAsync(order);
await dbContext.SaveChangesAsync();
await eventPublisher.PublishAsync(
new OrderCreatedIntegrationEvent(...));
What happens if:
SaveChangesAsync()
↓
SUCCESS
PublishAsync()
↓
FAIL
Now:
Order Database
↓
Order exists
Message Broker
↓
No OrderCreated event
Other microservices never know about the order.
This creates an inconsistency.
22. Transactional Outbox Pattern
A common production solution is the Transactional Outbox Pattern.
Instead of:
Save DB
↓
Publish directly
we do:
Order Service
↓
Database Transaction
│
├── Insert Order
│
└── Insert Outbox Event
│
▼
COMMIT
Both records succeed or fail together.
Then:
Outbox Background Worker
↓
Read unpublished events
↓
Message Broker
↓
Mark event published
Full flow:
Client
↓
Order Service
↓
┌─────────────────────────────┐
│ SQL Transaction │
│ │
│ INSERT Order │
│ INSERT OutboxMessage │
│ │
│ COMMIT │
└──────────────┬──────────────┘
│
▼
Outbox Processor
│
▼
Message Broker
│
▼
Subscribers
This is a very important pattern for Integration Events.
23. Idempotency
Even with an Outbox, consumers should consider duplicate delivery.
Suppose:
EventId = ABC123
is processed successfully.
But before acknowledgement:
Network failure
The broker may redeliver the message.
Consumer should be able to recognize:
ABC123
↓
Already processed
↓
Do not perform business action again
For example:
if (await processedEvents.ExistsAsync(
integrationEvent.EventId))
{
return;
}
await ProcessEventAsync(integrationEvent);
await processedEvents.AddAsync(
integrationEvent.EventId);
This is an Idempotent Consumer approach.
24. Integration Event Versioning
Integration Events are external contracts.
Suppose V1 is:
{
"orderId": 1001,
"amount": 2500
}
Later you need:
{
"orderId": 1001,
"amount": 2500,
"currency": "INR"
}
You must consider existing consumers.
This is why integration event contracts should be changed carefully.
Common approaches include:
Backward-compatible changes
Optional/new fields
Schema version
New event version when necessary
For example:
OrderCreatedV1
OrderCreatedV2
depending on your compatibility strategy.
25. Integration Event Metadata
A production Integration Event often includes metadata such as:
EventId
EventType
OccurredAt
CorrelationId
CausationId
SchemaVersion
Source
Example:
{
"eventId": "evt-10001",
"eventType": "OrderCreated",
"version": 1,
"correlationId": "corr-5001",
"occurredAt": "2026-09-29T10:30:00Z",
"orderId": 1001,
"customerId": 501,
"totalAmount": 2500,
"currency": "INR"
}
This improves:
Tracing
Debugging
Observability
Versioning
Duplicate detection
Auditing
26. Integration Event Naming
Good names normally describe something that already happened:
OrderCreated
OrderCancelled
PaymentCompleted
PaymentFailed
CustomerRegistered
InventoryReserved
ShipmentCreated
Avoid command-like event names:
CreateOrder ❌
ProcessPayment ❌
SendEmail ❌
Those express instructions.
Better:
OrderCreated ✓
PaymentCompleted ✓
EmailSent ✓
27. Integration Event vs Domain Event vs Command
| Concept | Meaning | Example | Scope |
|---|---|---|---|
| Command | Please do something | ProcessPayment |
Target handler |
| Domain Event | Something happened in this domain | OrderCreatedDomainEvent |
Inside bounded context |
| Integration Event | Other systems should know this happened | OrderCreatedIntegrationEvent |
Across services |
A useful flow is:
CreateOrderCommand
↓
Order Service
↓
OrderCreatedDomainEvent
↓
Internal Processing
↓
OrderCreatedIntegrationEvent
↓
Message Broker
↓
Other Microservices
28. Do We Need Both Domain Event and Integration Event?
Not always.
For a simple microservice, you might directly create an Integration Event after processing the business operation.
But in a more domain-driven architecture, separating them is useful because:
Domain Event
↓
Internal domain concern
Integration Event
↓
External service contract
This prevents your internal domain model from becoming coupled to external consumers.
29. Where Should Integration Events Be Placed?
In a Clean Architecture-style microservice, you might have:
OrderService
│
├── Domain
│ └── Events
│ └── OrderCreatedDomainEvent.cs
│
├── Application
│ └── IntegrationEvents
│ └── OrderCreatedIntegrationEvent.cs
│
├── Infrastructure
│ └── Messaging
│ └── AzureServiceBusPublisher.cs
│
└── API
However, if multiple independently deployed services need to deserialize the same contract, don't solve that by sharing your entire Application or Domain assembly.
A small dedicated contracts package can be used where appropriate:
Ordering.Contracts
↓
OrderCreatedIntegrationEvent
The important principle is:
Share the integration contract, not the service's internal domain model.
30. Advantages
Loose Coupling
Publisher doesn't directly depend on consumers.
Independent Services
Subscribers can evolve and deploy independently.
Multiple Subscribers
OrderCreated
├──> Inventory
├──> Notification
└──> Analytics
Asynchronous Processing
Publisher doesn't have to wait for all consumers.
Extensibility
New consumers can subscribe later.
Event-Driven Architecture
Integration Events are a core building block for event-driven microservices.
31. Disadvantages
Integration Events also introduce complexity:
- Eventual consistency
- Message broker infrastructure
- Duplicate processing
- Retry handling
- Dead-letter handling
- Event ordering
- Schema evolution
- Distributed tracing
- Monitoring
- More difficult debugging
That's why patterns such as:
Transactional Outbox
Idempotent Consumer
Correlation ID
DLQ
Retry
Schema Versioning
become important.
32. Key Points
For interview preparation:
- An Integration Event communicates an important occurrence across service boundaries.
- It is commonly published through a Message Broker.
OrderCreatedIntegrationEventis a typical example.- Integration Events are commonly used with Publish/Subscribe.
- They help achieve loose coupling between microservices.
- They commonly participate in Event-Driven Architecture.
- An Integration Event is an external contract.
- Don't expose the entire Domain Entity as an Integration Event.
- Domain Events are primarily internal to the bounded context.
- Integration Events communicate with other bounded contexts/services.
- Commands request actions; Integration Events announce facts.
- Events are generally named in the past tense.
- Integration Events often lead to eventual consistency.
- Use Transactional Outbox when reliable DB + event publication matters.
- Consumers should be idempotent.
- Plan for schema/version evolution.
- Include metadata such as EventId and CorrelationId where appropriate.
33. Interview Questions and Answers
Q1. What is an Integration Event?
Answer:
An Integration Event is a message published by one microservice to notify other microservices or external systems that an important business event has occurred.
For example:
OrderCreatedIntegrationEvent
can notify Inventory, Notification, and Analytics services.
Q2. Why do we need Integration Events?
Answer:
Integration Events allow microservices to communicate asynchronously without directly depending on each other. They provide loose coupling and are commonly used in Event-Driven Architecture.
Q3. What is the difference between Domain Event and Integration Event?
Answer:
A Domain Event primarily represents something that happened inside a bounded context.
An Integration Event communicates an appropriate representation of that occurrence to other services or bounded contexts.
Domain Event
→ Internal
Integration Event
→ External
Q4. Give an example.
Answer:
Order Service creates an order:
OrderCreatedIntegrationEvent
is published.
Then:
Inventory Service
→ Reserve/update inventory
Notification Service
→ Send confirmation
Analytics Service
→ Record order statistics
Q5. Integration Event vs Command?
Answer:
A Command requests an action:
ProcessPayment
An Integration Event announces an occurrence:
PaymentCompleted
Q6. Should Integration Events contain Domain Entities?
Answer:
Generally, no.
Integration Events should have dedicated contracts containing only the information external consumers need. Publishing the entire domain entity tightly couples consumers to the producer's internal model.
Q7. Should Integration Events be immutable?
Answer:
They should generally be treated as immutable facts. Once an event has been published, consumers may have already processed or stored it.
Q8. What happens if publishing fails after the database is updated?
Answer:
The system could become inconsistent. A common production solution is the Transactional Outbox Pattern, where the business change and outbox event are saved in the same database transaction and a separate worker subsequently publishes the event.
Q9. Can an Integration Event be delivered more than once?
Answer:
Yes, depending on the broker and failure scenario. Therefore consumers should be designed to be idempotent when duplicate effects matter.
Q10. Which technologies can publish Integration Events?
Answer:
Common options include:
Azure Service Bus
RabbitMQ
Apache Kafka
AWS SNS/SQS
Google Cloud Pub/Sub
The Integration Event is the architectural concept; the broker is the transport infrastructure.
Interview-Friendly Final Answer
An Integration Event is an event used to communicate an important business occurrence from one microservice or bounded context to other services. For example, after Order Service successfully creates an order, it can publish an
OrderCreatedIntegrationEventthrough Azure Service Bus, RabbitMQ, or Kafka. Inventory, Notification, and Analytics services can independently consume that event. Unlike a Domain Event, which is primarily internal to a bounded context, an Integration Event crosses service boundaries and acts as an external contract. In production, Integration Events should be designed with stable contracts, idempotent consumers, versioning, correlation IDs, and reliable publication patterns such as Transactional Outbox.