Business Events & Azure Integration
Master event-driven architecture in F&O β business events, custom business events, Azure Service Bus and Event Grid endpoints, HTTPS webhooks, and Azure Key Vault for secret management.
Business Events & Azure Integration
Every integration pattern we have covered so far involves someone asking F&O for data β polling, querying, exporting. Business events flip the model: F&O tells external systems when something happens. This is event-driven architecture, and it is the modern way to build loosely coupled, reactive integrations.
Think of business events like a news alert on your phone.
Instead of checking the news website every 5 minutes (polling), you subscribe to alerts and your phone buzzes when something happens (events). In F&O, when a sales order is confirmed or a payment is posted, the system sends a notification to any system that has subscribed. The subscriber decides what to do with it β send an email, update another system, trigger a workflow.
You decide what triggers the alert (the business event) and where it goes (the endpoint β Service Bus, Event Grid, or a web address).
The Business Events Framework
How it works
- Something happens in F&O β a business process reaches a milestone
- The application code raises a business event
- The framework checks if the event is activated for the current legal entity
- If activated, the event payload (JSON) is sent to the configured endpoint
- The external system receives and processes the event
π Marcusβs integration evolution: βWhen I started in this space, integrations meant nightly batch files and prayer. Business events changed everything. Now when Anitaβs finance team confirms a sales order, her warehouse system knows within seconds β not hours. And if the warehouse system is down? The message sits in Service Bus until it comes back online. That is reliability.β
Business Events Catalog
F&O ships with dozens of standard business events covering major business processes:
| Category | Example Events |
|---|---|
| Sales | Sales order confirmed, Sales order invoiced, Sales order packed |
| Purchasing | Purchase order approved, Purchase order confirmed |
| Finance | Free text invoice posted, Payment journal posted |
| Inventory | Transfer order shipped, Counting journal posted |
| Workflow | Work item created, Work item completed, Workflow approved |
| Batch | Batch job completed, Batch job failed |
| Alerts | Alert rule triggered (user-configured) |
You browse the full catalog in System administration β Setup β Business events β Business events catalog.
Activating Business Events
Business events must be activated before they fire. Activation is per-legal-entity:
- Go to Business events catalog
- Find your event (e.g., βSales order confirmedβ)
- Click Activate
- Select the legal entity (or all)
- Select the endpoint (where to send it)
π Marcusβs governance note: βNever activate all events to all endpoints β you will drown your downstream systems. Activate only the events each system needs. Anitaβs warehouse needs βSales order confirmedβ and βTransfer order shippedβ. That is it. Her finance reporting system needs βInvoice postedβ. Different systems, different events, different endpoints.β
Creating Custom Business Events
When standard events donβt cover your scenario, you build a custom business event. This involves three pieces:
1. Business event contract (payload)
Defines the data sent with the event.
[DataContractAttribute]
class CustCreditLimitExceededContract extends BusinessEventsContract
{
CustAccount custAccount;
AmountMST creditLimit;
AmountMST currentBalance;
str custName;
public static CustCreditLimitExceededContract
newFromCustTable(CustTable _custTable, AmountMST _balance)
{
CustCreditLimitExceededContract contract = new CustCreditLimitExceededContract();
contract.parmCustAccount(_custTable.AccountNum);
contract.parmCreditLimit(_custTable.CreditMax);
contract.parmCurrentBalance(_balance);
contract.parmCustName(_custTable.name());
// BusinessEventsContract requires legal entity context
contract.parmLegalEntity(_custTable.dataAreaId);
return contract;
}
[DataMemberAttribute('CustomerAccount')]
public CustAccount parmCustAccount(CustAccount _value = custAccount)
{
custAccount = _value;
return custAccount;
}
[DataMemberAttribute('CreditLimit')]
public AmountMST parmCreditLimit(AmountMST _value = creditLimit)
{
creditLimit = _value;
return creditLimit;
}
[DataMemberAttribute('CurrentBalance')]
public AmountMST parmCurrentBalance(AmountMST _value = currentBalance)
{
currentBalance = _value;
return currentBalance;
}
[DataMemberAttribute('CustomerName')]
public str parmCustName(str _value = custName)
{
custName = _value;
return custName;
}
}
2. Business event class
Defines the event itself β its ID, description, and contract.
[BusinessEventsAttribute('CustCreditLimitExceeded',
'Customer credit limit exceeded',
'Raised when a customer balance exceeds their credit limit',
ModuleAxapta::SalesOrder)]
class CustCreditLimitExceededEvent extends BusinessEventsBase
{
CustTable custTable;
AmountMST currentBalance;
public static CustCreditLimitExceededEvent
newFromCustTable(CustTable _custTable, AmountMST _balance)
{
CustCreditLimitExceededEvent event = new CustCreditLimitExceededEvent();
event.custTable = _custTable;
event.currentBalance = _balance;
return event;
}
protected BusinessEventsContract buildContract()
{
return CustCreditLimitExceededContract::newFromCustTable(
this.custTable, this.currentBalance);
}
}
3. Raising the event
Call this from the business logic where the event should fire.
// In the credit check logic
if (currentBalance > custTable.CreditMax)
{
CustCreditLimitExceededEvent businessEvent =
CustCreditLimitExceededEvent::newFromCustTable(custTable, currentBalance);
businessEvent.send();
}
Whatβs happening in the three pieces:
- The contract (
CustCreditLimitExceededContract) extendsBusinessEventsContractand defines the JSON payload fields - The event class (
CustCreditLimitExceededEvent) extendsBusinessEventsBase, carries theBusinessEventsAttributethat registers it in the catalog, and builds the contract inbuildContract() - The
send()method checks if the event is activated for the current legal entity and delivers it to configured endpoints
ποΈ Vikβs code review: βThree things I always check in custom business events: (1) Does the contract inherit from BusinessEventsContract? (2) Is parmLegalEntity set? Without it, the event wonβt match any activation. (3) Is send() called inside a ttsCommit block? Events should only fire after the transaction succeeds β never on a path that might roll back.β
Exam tip: BusinessEventsContract base class
The exam will test whether you know that custom business event contracts must extend BusinessEventsContract (not just DataContractAttribute). The base class provides parmLegalEntity, parmBusinessEventId, and serialization support. If your contract extends a plain class, the business events framework wonβt recognise it.
Endpoints
Endpoints define where business events are delivered. F&O supports four endpoint types.
Azure Service Bus
The most common endpoint for enterprise integrations. Service Bus provides:
- Queues β point-to-point messaging (one consumer per message)
- Topics β publish-subscribe (multiple consumers per message)
- Dead-letter queue β failed messages are preserved for investigation
- Guaranteed delivery β messages persist until consumed
Configuration: Provide the Service Bus connection string and queue/topic name.
Azure Event Grid
For high-throughput, low-latency event routing. Event Grid excels at:
- Fan-out to many subscribers
- Filtering events at the platform level
- Serverless triggers (Azure Functions, Logic Apps)
Configuration: Provide the Event Grid topic endpoint and access key.
HTTPS Webhook
A simple POST to any HTTPS URL. The event payload is the request body.
- Simplest to set up
- No guaranteed delivery β if the endpoint is down, the event is lost (unless you add retry logic)
- Good for: Power Automate custom connectors, third-party SaaS webhooks
Microsoft Power Automate
A direct integration β business events trigger Power Automate flows without any intermediate infrastructure.
- Use the Finance and Operations connectorβs When a business event occurs trigger
- No need to configure Service Bus or Event Grid
- Perfect for: approval workflows, email notifications, Teams alerts
| Endpoint | Delivery | Reliability | Best For |
|---|---|---|---|
| Azure Service Bus | Queue/Topic | Guaranteed (persist until consumed) | Enterprise middleware, high-reliability integrations |
| Azure Event Grid | Push (HTTP) | At-least-once with retry | High-throughput fan-out, serverless triggers |
| HTTPS Webhook | POST to URL | No guarantee (fire-and-forget) | Simple integrations, third-party SaaS |
| Power Automate | Direct trigger | Platform-managed retry | Low-code workflows, notifications, approvals |
Azure Key Vault Integration
Business event endpoints need connection strings, access keys, and secrets. Hardcoding these is a security risk. Azure Key Vault provides secure, centralised secret management.
How F&O uses Key Vault
- Store secrets in Azure Key Vault (connection strings, API keys, certificates)
- Register the Key Vault in F&O (System administration β Setup β Azure Key Vault parameters)
- Reference secrets by name when configuring endpoints, certificates, or external connections
- F&O retrieves the secret at runtime β the value never appears in F&O configuration
Configuration steps
- Create a Key Vault in Azure
- Register an app in Entra ID for F&O to authenticate to Key Vault
- Grant the app
GetandListpermissions on Key Vault secrets - In F&O: System administration β Setup β Key Vault parameters
- Enter the Key Vault URL (e.g.,
https://nexbridge-vault.vault.azure.net/) - Enter the app registrationβs client ID and secret
- Enter the Key Vault URL (e.g.,
- Add secrets β map friendly names to Key Vault secret names
- Reference the friendly names in endpoint configurations
π Marcusβs security stance: βRafiq asked why we canβt just paste the Service Bus connection string directly into the endpoint config. Three reasons: (1) the connection string is visible to anyone who can view the endpoint setup, (2) when you rotate the key, you have to update every endpoint manually, and (3) it violates every security audit checklist I have ever seen. Key Vault or nothing.β
Exam tip: Key Vault vs endpoint configuration
The exam tests whether you know that secrets in F&O endpoint configurations should come from Azure Key Vault β not pasted directly. If a question asks βhow to securely store the Service Bus connection string for a business event endpointβ, the answer is Azure Key Vault. Also remember: F&O needs an Entra ID app registration with Key Vault access permissions β it cannot access Key Vault anonymously.
Event-Driven Architecture Patterns
Pattern 1: Event β Service Bus β Multiple Consumers
F&O: Invoice Posted
β
βββ Service Bus Topic
β
βββ Subscription 1 β Reporting System (update dashboard)
βββ Subscription 2 β Email Service (send receipt)
βββ Subscription 3 β Archive System (store document)
One event, multiple subscribers, each processing independently. If one fails, the others are unaffected.
Pattern 2: Event β Power Automate β Action
F&O: Purchase Order Approved
β
βββ Power Automate
β
βββ Send Teams notification to buyer
βββ Create task in Planner
βββ Update SharePoint tracking list
Low-code workflow triggered directly by a business event.
Pattern 3: Event β Event Grid β Azure Functions
F&O: Inventory Below Threshold
β
βββ Event Grid
β
βββ Azure Function
β
βββ Call supplier API for reorder
βββ Log to Application Insights
Serverless compute reacting to business events.
π Marcusβs architecture principle: βThe beauty of event-driven is decoupling. F&O doesnβt know or care what happens after it fires the event. The warehouse system, the email service, the reporting dashboard β they all subscribe independently. If we add a new consumer next month, F&O doesnβt change at all.β
Business events vs alerts vs database events
F&O has three event-like features β donβt confuse them:
- Business events: Developer-defined events raised at business process milestones. External-facing. JSON payloads delivered to endpoints.
- Alerts: User-configured notifications for record changes (e.g., βnotify me when a customer is createdβ). Internal to F&O β trigger email or Action Centre notifications, or business events if configured.
- Database events: Low-level change tracking for internal sync (dual-write, change tracking). Not directly consumable as integration events.
The exam may present scenarios where each is appropriate. Business events = external integration. Alerts = internal user notification. Database events = sync infrastructure.
Exam Practice
When a sales order is confirmed in F&O, a warehouse system, a reporting dashboard, and an email service all need to be notified. Which endpoint type should Marcus configure?
Vik creates a custom business event contract but forgets to extend BusinessEventsContract. What happens?
Marcus needs to store the Azure Service Bus connection string for a business event endpoint. Where should it be stored?
Which of the following correctly describes the relationship between BusinessEventsBase and BusinessEventsContract?
Domain 6 complete! π You have covered the full integration landscape β from choosing the right pattern and API, through DMF and custom services, to dual-write, virtual entities, and event-driven architecture.
Next up: Domain 7 β Security: Roles, Duties, Privileges & XDS β implement security architecture and optimise performance.