---
# === IDENTITY ===
id: business/erp-integration/ifs-event-architecture/2026
canonical_question: "How does the IFS Event Architecture work for event-driven integration?"
aliases:
  - "IFS Cloud ECA event actions and custom events for integration"
  - "How to configure IFS event-driven webhooks and REST call actions"
  - "IFS Cloud event registry, event actions, and workflow triggers"
  - "IFS Streams and event notification architecture for external consumers"
entity_type: erp_integration
domain: business > erp-integration > ifs-event-architecture
region: global
jurisdiction: global
temporal_scope: 2024-2026

# === SYSTEM PROFILE ===
systems:
  - name: "IFS Cloud"
    vendor: "IFS"
    version: "24R2 / 25R1"
    edition: "All editions"
    deployment: "cloud"
    api_surface: "Event Framework (ECA) + OData REST"

# === VERIFICATION ===
last_verified: 2026-03-03
confidence: 0.84
version: 1.0
first_published: 2026-03-03

# === TEMPORAL VALIDITY ===
temporal_validity:
  status: volatile
  last_breaking_change: "23R1 — workflow triggering via custom commands added; Camunda REST API integration"
  next_review: 2026-08-30
  change_sensitivity: high

# === CONSTRAINTS ===
constraints:
  - "Event actions execute within the database transaction — Execute Online SQL actions that fail roll back the triggering transaction"
  - "Custom events fire via database triggers — enabling too many custom events on high-volume tables degrades insert/update performance"
  - "REST Call event actions have no built-in logging — failures in outbound REST calls are silent unless you implement external monitoring"
  - "Push notifications (Streams) are fire-and-forget with no replay — missed events during consumer downtime are lost"
  - "IFS REST Call delegate in Workflows lacks advanced authentication beyond None, Bearer Token, and OAuth 2.0 — no HMAC, API key headers, or mTLS"
  - "Event actions of type Execute Online SQL require elevated permissions — misconfigured SQL can corrupt data or cause cascading transaction rollbacks"

# === SKIP CONDITIONS ===
skip_this_unit_if:
  - condition: "User needs IFS OData REST API for CRUD operations, not event-driven patterns"
    use_instead: "business/erp-integration/ifs-odata-api/2026"
  - condition: "User needs a different ERP system event architecture (e.g., Salesforce Platform Events)"
    use_instead: "business/erp-integration/salesforce-platform-events/2026"
  - condition: "User needs IFS Cloud Workflow design and BPMN modeling, not event triggers"
    use_instead: "business/erp-integration/ifs-workflow-engine/2026"

# === AGENT HINTS ===
inputs_needed:
  - key: integration_pattern
    question: "What integration pattern do you need?"
    type: choice
    options:
      - "real-time sync (individual records, <1s latency)"
      - "batch/bulk (scheduled, high volume)"
      - "event-driven (webhook, CDC, platform events)"
      - "file-based (CSV/XML import/export)"
  - key: data_volume
    question: "What's your daily data volume?"
    type: choice
    options:
      - "< 1,000 records/day"
      - "1,000-100,000 records/day"
      - "> 100,000 records/day"
  - key: direction
    question: "What's the data flow direction?"
    type: choice
    options:
      - "inbound (writing to IFS Cloud)"
      - "outbound (reading/reacting from IFS Cloud)"
      - "bidirectional sync"

# === DISTRIBUTION ===
canonical_source: "https://knowledgelib.io/business/erp-integration/ifs-event-architecture/2026"
suggested_citation: "Source: knowledgelib.io — AI Knowledge Library (verified 2026-03-03)"

# === RELATED UNITS ===
related_kos:
  depends_on: []
  related_to:
    - id: "business/erp-integration/ifs-odata-api/2026"
      label: "IFS Cloud OData REST API for CRUD and projection access"
  solves:
    - id: "business/erp-integration/ifs-external-system-sync/2026"
      label: "Real-time sync playbook between IFS Cloud and external systems"
  alternative_to:
    - id: "business/erp-integration/ifs-connect-middleware/2026"
      label: "IFS Connect service bus for message-based integration (XML/XSLT)"
  often_confused_with:
    - id: "business/erp-integration/ifs-workflow-engine/2026"
      label: "IFS Cloud Workflows (Camunda BPMN) — orchestration, not event triggers"

# === SOURCES ===
sources:
  - id: src1
    title: "Events — IFS Foundation Technical Documentation"
    author: IFS
    url: https://docs.ifs.com/techdocs/Foundation1/040_administration/240_integration/320_events/
    type: official_docs
    published: 2025-01-15
    reliability: authoritative
  - id: src2
    title: "Manage Event Actions — IFS Cloud 24R1 Technical Documentation"
    author: IFS
    url: https://docs.ifs.com/techdocs/24r1/030_administration/090_automation_optimization/320_events/100_manage_events/
    type: official_docs
    published: 2024-06-01
    reliability: authoritative
  - id: src3
    title: "Event Registry — IFS Foundation Developer Documentation"
    author: IFS
    url: https://docs.ifs.com/techdocs/Foundation1/050_development/040_core_server/027_base_server_dev/040_framework-services/020_event_registry/
    type: official_docs
    published: 2025-01-15
    reliability: authoritative
  - id: src4
    title: "Start IFS Cloud Workflow using REST API"
    author: DSJ
    url: https://dsj23.me/2024/09/04/start-ifs-cloud-workflow-using-rest-api/
    type: technical_blog
    published: 2024-09-04
    reliability: moderate_high
  - id: src5
    title: "Send Data to a REST API using IFS Workflow"
    author: DSJ
    url: https://dsj23.me/2024/02/23/send-data-to-a-rest-api-using-ifs-workflow/
    type: technical_blog
    published: 2024-02-23
    reliability: moderate_high
  - id: src6
    title: "Authentication, Authorization and Initialization in the OData API of IFS Cloud"
    author: Novacura
    url: https://www.novacura.com/the-odata-api-of-ifs-cloud-and-authentication/
    type: technical_blog
    published: 2024-08-15
    reliability: moderate_high
  - id: src7
    title: "IFS Cloud Workflows: Enabling Business Process Adjustments"
    author: IFS ERP Consulting
    url: https://ifs-erp.consulting/ifs-cloud/ifs-cloud-workflows
    type: technical_blog
    published: 2024-11-01
    reliability: moderate_high
---

# IFS Event Architecture: ECA Rules, Event Actions, and Event-Driven Integration Guide

## TL;DR

- **Bottom line**: IFS Cloud uses an ECA (Event-Condition-Action) rule engine embedded in the database layer. Events fire on entity changes (insert/update/delete), conditions filter which changes matter, and actions execute responses — from emails and REST calls to workflow triggers and SQL execution. This is IFS's primary mechanism for outbound event-driven integration. [src1, src3]
- **Key limit**: Custom events fire via database triggers — enabling many custom events on high-transaction tables directly impacts database write performance. System-defined events are optimized by IFS; custom events are not. [src1, src3]
- **Watch out for**: Execute Online SQL event actions run within the triggering transaction. If the SQL fails, the entire business transaction rolls back — not just the event action. This can cause user-facing errors that are extremely difficult to diagnose. [src1, src2]
- **Best for**: Outbound notifications, webhook-style REST call-outs to external systems, triggering IFS Workflows on business entity changes, and sending conditional email alerts — all without writing custom server-side code. [src1, src2]
- **Authentication**: IFS Cloud APIs use OAuth 2.0 (via IFS IAM) with OpenID Connect. Basic auth is available but explicitly not recommended for production. Projection-level permissions control access to specific OData endpoints. [src6]

## System Profile

IFS Cloud is an enterprise ERP platform focused on asset-intensive industries (aerospace, defense, energy, manufacturing, construction). Its event architecture is built into the Oracle database layer, implementing the ECA (Event-Condition-Action) pattern directly in PL/SQL business logic. The Event Registry manages all event definitions, conditions, and action mappings. Events can trigger seven different action types including REST calls for webhook-style outbound integrations, Workflow starts via the embedded Camunda engine, and Streams notifications for in-app messaging. This card covers the event framework across all IFS Cloud editions (24R2 and 25R1). IFS Connect (the message-based service bus) and the OData REST API are separate integration surfaces not covered in depth here. [src1, src3, src7]

| Property | Value |
|---|---|
| **Vendor** | IFS |
| **System** | IFS Cloud 24R2 / 25R1 |
| **API Surface** | Event Framework (ECA) + OData REST |
| **Current Version** | Foundation1 / 24R2 |
| **Editions Covered** | All editions |
| **Deployment** | Cloud (SaaS) / Hybrid / On-Premise |
| **API Docs URL** | [IFS Events Documentation](https://docs.ifs.com/techdocs/Foundation1/040_administration/240_integration/320_events/) |
| **Status** | GA |

## API Surfaces & Capabilities

IFS Cloud provides multiple integration surfaces. The Event Framework is the primary mechanism for outbound, reactive integrations. [src1, src3, src6]

| API Surface | Protocol | Best For | Max Records/Request | Rate Limit | Real-time? | Bulk? |
|---|---|---|---|---|---|---|
| Event Framework (ECA) | PL/SQL / Database triggers | Outbound notifications, webhook REST calls, workflow triggers | Per-event (single entity change) | No explicit rate limit (DB transaction-bound) | Yes | No |
| OData REST API (Projections) | HTTPS/JSON (OData v4) | CRUD operations, queries, integrations | Configurable (5,000+ projections) | Fair-use / throttled | Yes | Partial (paged) |
| IFS Connect | XML/XSLT message bus | Async message routing, connector-based integrations | Per-message | Depends on routing config | Async | No |
| Workflows (Camunda) | REST / BPMN | Multi-step process orchestration, human tasks | N/A | N/A | Yes | N/A |
| Streams Notifications | Internal messaging | In-app user notifications | N/A | N/A | Yes | N/A |
| Application Messages | XML via connectors | B2B integrations (EDI, partner connectors) | Per-message | Connector-dependent | Async | No |

[src1, src3, src6, src7]

## Rate Limits & Quotas

### Per-Request Limits

IFS Cloud does not publish explicit per-request rate limits for the event framework. Events fire synchronously within database transactions, so throughput is bounded by database capacity and transaction volume. [src1, src3]

| Limit Type | Value | Applies To | Notes |
|---|---|---|---|
| Event actions per event | No hard limit | Event Framework | Multiple actions can be registered per event; all execute sequentially within the transaction [src1] |
| REST Call timeout | Configurable (default varies) | REST Call event action | Outbound REST calls that exceed timeout silently fail; no retry [src2] |
| Streams message recipients | User-scoped | Streams Message action | Notifications delivered only to Foundation1 users [src1] |
| Execute Online SQL scope | Single transaction | Execute Online SQL action | SQL runs within the triggering transaction — failure rolls back everything [src1] |

[src1, src2]

### Rolling / Daily Limits

| Limit Type | Value | Window | Edition Differences |
|---|---|---|---|
| OData API requests | Fair-use / throttled | Per-session | Not edition-specific; IFS manages throttling at the proxy layer [src6] |
| Concurrent API sessions | Tenant-dependent | Per-tenant | Controlled by IFS IAM; exact limits depend on deployment topology [src6] |
| Workflow engine capacity | Instance-dependent | Per-instance | Camunda engine throughput depends on infrastructure sizing [src4] |
| Application Message throughput | Connector-dependent | Per-connector | IFS Connect routing rules control message flow rates [src1] |

[src1, src6]

## Authentication

IFS Cloud uses OAuth 2.0 via the IFS Identity and Access Manager (IFS IAM) for API access. The event framework itself does not require separate authentication — it fires within the server-side database session. Outbound REST Call event actions can include authentication headers. [src6]

| Flow | Use When | Token Lifetime | Refresh? | Notes |
|---|---|---|---|---|
| OAuth 2.0 Client Credentials | Server-to-server integration, scheduled jobs | Configurable via IFS IAM | Yes | Recommended for integrations [src6] |
| OAuth 2.0 Authorization Code | User-context operations, interactive applications | Session-dependent | Yes | Requires redirect URI configuration [src6] |
| Basic Authentication | Data migration, one-time imports only | Session timeout | No | Explicitly not recommended for production or 3rd-party integrations [src6] |
| Bearer Token (REST Call action) | Outbound REST calls from event actions | Pre-configured | No | Token must be configured in event action setup; no auto-refresh [src5] |
| OAuth 2.0 (Workflow REST Call) | Outbound REST calls from Camunda workflows | Per-request | Yes | Supported in IFS REST Call delegate [src5] |

[src5, src6]

### Authentication Gotchas

- **No user impersonation in OData**: Unlike legacy PL/SQL sessions that could switch user context, OData API calls cannot impersonate other users. The authenticated user's permissions apply to all operations within that session. [src6]
- **Projection-level authorization**: Permissions in IFS Cloud are controlled at the projection level, not through traditional database roles. An integration user must be granted access to each specific projection it needs to query. [src6]
- **REST Call event actions do not auto-refresh tokens**: If an outbound REST call uses a Bearer Token, the token is static. When it expires, the event action silently fails. Implement token refresh logic in the receiving system or use OAuth 2.0 flow in Workflow delegates instead. [src5]
- **IFS IAM is the single authentication gateway**: All API access flows through IFS IAM. If IAM is unavailable, both inbound API calls and outbound OAuth-authenticated event actions fail. [src6]

## Constraints

- **Execute Online SQL actions run within the triggering transaction** — if the SQL statement fails (syntax error, constraint violation, deadlock), the entire business operation that triggered the event is rolled back. Users see a generic error with no indication that an event action caused the failure. [src1, src2]
- **Custom events use database triggers** — IFS creates Oracle database triggers when custom events are enabled. On high-volume tables (e.g., inventory transactions, work order operations), this adds overhead to every insert/update/delete. System-defined events are embedded in the PL/SQL business logic and are more performant. [src1, src3]
- **REST Call event actions are fire-and-forget** — there is no built-in retry mechanism, dead letter queue, or delivery confirmation. If the target endpoint is down, the event action fails silently. [src2, src5]
- **Streams notifications are not for external systems** — Streams messages are delivered only within the IFS Cloud UI to Foundation1 users. They cannot be consumed by external applications or message brokers. [src1]
- **IFS REST Call Workflow delegate has limited capabilities** — it does not support advanced authentication (HMAC, API keys in custom headers, mTLS), response header processing, or structured JSON/XML parsing. Complex response handling requires additional workflow logic. [src5]
- **Application Message routing requires IFS Connect configuration** — to route events to external systems via XML/XSLT transformation, you must configure IFS Connect connectors, which requires specialized IFS administration knowledge. [src1]

## Integration Pattern Decision Tree

```
START — User needs event-driven integration with IFS Cloud
|-- What's the event source?
|   |-- IFS Cloud entity change (insert/update/delete)
|   |   |-- System-defined event exists for this entity?
|   |   |   |-- YES --> Use system-defined event (better performance) [src1]
|   |   |   |-- NO --> Create custom event on the entity's base table [src1, src3]
|   |   |-- What action do you need?
|   |       |-- Notify external system (webhook)?
|   |       |   |-- YES --> REST Call event action [src2]
|   |       |   |-- Complex multi-step process? --> Start Workflow event action [src4, src7]
|   |       |-- Send email notification?
|   |       |   |-- YES --> E-Mail event action [src1]
|   |       |-- Execute database logic?
|   |       |   |-- YES --> Execute Online SQL (CAUTION: runs in same transaction) [src1]
|   |       |-- Notify IFS users in-app?
|   |       |   |-- YES --> Streams Message event action [src1]
|   |       |-- Route to middleware (IFS Connect)?
|   |           |-- YES --> Application Message event action [src1]
|   |-- External system pushes data TO IFS Cloud?
|       |-- YES --> Use OData REST API (POST/PUT via projections) [src6]
|       |-- Need complex transformation? --> IFS Connect inbound connector [src1]
|-- What's the timing requirement?
|   |-- Real-time (<1s after entity change)
|   |   |-- REST Call event action (synchronous within transaction) [src2]
|   |-- Near real-time (seconds to minutes)
|   |   |-- Start Workflow --> Camunda orchestrates async REST calls [src4, src5]
|   |-- Batch/scheduled
|       |-- OData API polling with date filter (not event-driven) [src6]
|-- Error tolerance?
    |-- Zero-loss required --> Use Workflow with error handling + IFS Connect with retry [src4, src5]
    |-- Best-effort acceptable --> REST Call event action (fire-and-forget) [src2]
```

## Quick Reference

### Event Action Types

| Action Type | Purpose | Execution Context | External? | Retry? | Notes |
|---|---|---|---|---|---|
| E-Mail | Send email notifications | Async (mail queue) | Yes (SMTP) | Mail server retry | Supports substitution fields for dynamic content [src1] |
| Execute Online SQL | Run PL/SQL/SQL statements | Synchronous (same transaction) | No | No | CAUTION: failure rolls back triggering transaction [src1] |
| Application Message | Route to IFS Connect | Async (message queue) | Yes (via connector) | Connector-dependent | Supports XSLT transformation [src1] |
| Task | Create user assignment | Synchronous | No | N/A | Visible in Enterprise Explorer [src1] |
| Start Workflow | Trigger Camunda workflow | Async (workflow engine) | Yes (via workflow) | Workflow-defined | Primary mechanism for complex multi-step integrations [src4, src7] |
| Streams Message | In-app notification | Async | No | N/A | Foundation1 users only [src1] |
| REST Call | Outbound HTTP request | Synchronous | Yes | No | Webhook-style integration; fire-and-forget [src2] |

### Event Parameter Substitution Fields

| Field Type | Syntax | Example | Notes |
|---|---|---|---|
| New value after change | `NEW:{AttributeName}` | `NEW:ORDER_STATUS` | Available for insert and update events [src1, src3] |
| Old value before change | `OLD:{AttributeName}` | `OLD:ORDER_STATUS` | Available for update and delete events [src1, src3] |
| Event-specific field | `&{FieldName}` | `&EVENT_DATETIME` | Standard parameters like datetime, user, rowkey [src3] |
| Context variable | `#{ContextVar}` | `#USER_IDENTITY` | System-level context: user, mail, phone [src3] |

## Step-by-Step Integration Guide

### 1. Identify or create the event

Navigate to IFS Solution Manager > Events. Check if a system-defined event already exists for your entity (e.g., CustomerOrder, InventoryTransaction). If not, create a custom event by selecting the Logical Unit and specifying the trigger type (New, Modify, Remove) and timing (Before or After). [src1, src3]

```plaintext
Steps in IFS Cloud:
1. Navigate to Solution Manager > Events
2. Search for your target entity (Logical Unit name)
3. If a system-defined event exists:
   - Click to view — note it is read-only except for subscriptions
4. If no system event exists, create a Custom Event:
   - Click "+" to add new event
   - Select the Logical Unit (e.g., CustomerOrderLine)
   - Set trigger: "New" (insert), "Modify" (update), or "Remove" (delete)
   - Set timing: "After" (post-commit, safer) or "Before" (pre-commit, can block)
   - Select attributes to expose as NEW: and OLD: parameters
   - Enable the event
```

**Verify**: The event appears in the Event list with status "Enabled". For custom events, verify the database trigger was created.

### 2. Define conditions for the event action

Add conditions that filter when the action should execute. Conditions use the parameter values from step 1 to evaluate whether the action should fire. [src1]

```plaintext
Condition configuration:
1. Open the event action configuration
2. Add conditions using parameter substitution:
   - Example: NEW:ORDER_STATUS = 'Released' AND OLD:ORDER_STATUS != 'Released'
   - This fires only when status transitions TO 'Released'
3. Multiple conditions are AND-ed by default
4. Leave conditions empty to fire on every event occurrence
```

**Verify**: Test by modifying a record that matches the condition and one that does not. Only the matching record should trigger the action.

### 3. Configure a REST Call event action (webhook)

Create an event action of type "REST Call" to notify an external system when the event fires. [src2]

```plaintext
REST Call event action setup:
1. In Event Actions, click "+" to add new action
2. Set Action Type: "REST Call"
3. Configure:
   - URL: https://external-system.example.com/webhook/ifs-event
   - Method: POST
   - Headers: Content-Type: application/json
   - Body (JSON with substitution fields):
     {
       "event": "order_status_change",
       "order_no": "NEW:ORDER_NO",
       "old_status": "OLD:ORDER_STATUS",
       "new_status": "NEW:ORDER_STATUS",
       "changed_by": "#USER_IDENTITY",
       "timestamp": "&EVENT_DATETIME"
     }
4. Authentication: Bearer Token (if required by target)
5. Enable the event action
```

**Verify**: Change a record matching the event condition. Check the external system's webhook endpoint logs for the incoming POST request.

### 4. Configure a Workflow event action (complex orchestration)

For multi-step integrations requiring error handling, human tasks, or sequential REST calls, trigger a Camunda workflow instead of a direct REST call. [src4, src7]

```plaintext
Workflow event action setup:
1. In Event Actions, click "+" to add new action
2. Set Action Type: "Workflow"
3. Reference the deployed Workflow process definition key
4. Map event parameters to workflow input variables:
   - ORDER_NO --> orderNumber (workflow variable)
   - NEW:STATUS --> newStatus (workflow variable)
5. Enable the event action

The workflow then handles:
- Multiple outbound REST calls with retry logic
- Human approval tasks if needed
- Error handling and compensation
```

**Verify**: Trigger the event. Check the IFS Workflow Monitor for a new workflow instance. Verify the workflow executed all expected steps.

### 5. Start a workflow via REST API (external trigger)

External systems can invoke IFS Workflows directly via the Camunda REST API exposed through IFS Cloud. [src4]

```bash
# Input:  IFS Cloud URL, OAuth access token, workflow process key
# Output: Workflow instance ID and execution variables

# Get OAuth token from IFS IAM
TOKEN=$(curl -s -X POST "https://yourifs.cloud/auth/realms/ifs/protocol/openid-connect/token" \
  -d "grant_type=client_credentials" \
  -d "client_id=YOUR_CLIENT_ID" \
  -d "client_secret=YOUR_CLIENT_SECRET" \
  | python3 -c "import sys,json;print(json.load(sys.stdin)['access_token'])")

# Start a workflow instance
curl -X POST \
  "https://yourifs.cloud/main/ifsapplications/projection/engine-rest/process-definition/key/MyIntegrationWorkflow/start" \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "withVariablesInReturn": true,
    "variables": {
      "orderNumber": {"value": "CO-12345", "type": "String"},
      "integrationTarget": {"value": "external-erp", "type": "String"}
    }
  }'

# Response includes workflow instance ID and returned variables
```

**Verify**: `curl -H "Authorization: Bearer $TOKEN" "https://yourifs.cloud/main/ifsapplications/projection/engine-rest/history/process-instance?processDefinitionKey=MyIntegrationWorkflow&sortBy=startTime&sortOrder=desc&maxResults=1"` returns the started instance with status "COMPLETED".

### 6. Implement outbound REST calls from a Workflow

Use the IFS REST Call delegate (`IfsHttpConnectionDelegate`) within a Camunda workflow service task to call external REST APIs with response parsing. [src5]

```xml
<!-- Camunda service task configuration for REST Call delegate -->
<serviceTask id="callExternalApi" name="Call External System"
  camunda:delegateExpression="${ifsHttpConnectionDelegate}">
  <extensionElements>
    <camunda:inputOutput>
      <!-- HTTP Method -->
      <camunda:inputParameter name="ifsBpaHttpConnectionMethod">POST</camunda:inputParameter>
      <!-- Target URL -->
      <camunda:inputParameter name="ifsBpaHttpConnectionUrl">
        https://external-system.example.com/api/orders
      </camunda:inputParameter>
      <!-- Request headers -->
      <camunda:inputParameter name="ifsBpaHttpConnectionHeaders">
        {"Content-Type": "application/json", "X-Source": "IFS-Cloud"}
      </camunda:inputParameter>
      <!-- Request body with workflow variables -->
      <camunda:inputParameter name="ifsBpaHttpConnectionBody">
        {"order_no": "${orderNumber}", "status": "${newStatus}"}
      </camunda:inputParameter>
      <!-- Parse response JSON -->
      <camunda:inputParameter name="ifsBpaHttpConnectionOutputs">
        {"externalId": "$.id", "confirmationCode": "$.confirmation"}
      </camunda:inputParameter>
      <!-- Check response status -->
      <camunda:inputParameter name="ifsBpaRestResponseCheck">true</camunda:inputParameter>
    </camunda:inputOutput>
  </extensionElements>
</serviceTask>
```

**Verify**: After the workflow completes, check that `externalId` and `confirmationCode` variables are populated in the workflow history.

## Code Examples

### Python: Listen for IFS webhook events and process them

```python
# Input:  Incoming HTTP POST from IFS REST Call event action
# Output: Processed event data, logged and acknowledged

# pip install flask==3.x
from flask import Flask, request, jsonify
import logging
import json
from datetime import datetime

app = Flask(__name__)
logging.basicConfig(level=logging.INFO)

@app.route("/webhook/ifs-event", methods=["POST"])
def handle_ifs_event():
    """Receive and process IFS Cloud event action webhooks."""
    try:
        payload = request.get_json(force=True)
        event_type = payload.get("event", "unknown")
        timestamp = payload.get("timestamp", datetime.utcnow().isoformat())

        logging.info(f"IFS event received: {event_type} at {timestamp}")
        logging.info(f"Payload: {json.dumps(payload, indent=2)}")

        # Process based on event type
        if event_type == "order_status_change":
            order_no = payload.get("order_no")
            new_status = payload.get("new_status")
            logging.info(f"Order {order_no} changed to {new_status}")
            # Add your business logic here

        # IFS REST Call action expects 2xx response
        return jsonify({"status": "received", "event": event_type}), 200

    except Exception as e:
        logging.error(f"Error processing IFS event: {e}")
        # Return 200 anyway to prevent IFS transaction issues
        # (IFS REST Call has no retry — log and handle async)
        return jsonify({"status": "error", "message": str(e)}), 200

if __name__ == "__main__":
    app.run(host="0.0.0.0", port=8080)
```

### JavaScript/Node.js: Query IFS OData API with event-driven polling fallback

```javascript
// Input:  IFS Cloud instance URL, OAuth credentials
// Output: Changed records since last poll timestamp

// npm install axios@1.x
const axios = require("axios");

async function getIfsToken(ifsUrl, clientId, clientSecret) {
  const tokenUrl = `${ifsUrl}/auth/realms/ifs/protocol/openid-connect/token`;
  const resp = await axios.post(tokenUrl, new URLSearchParams({
    grant_type: "client_credentials",
    client_id: clientId,
    client_secret: clientSecret,
  }), { headers: { "Content-Type": "application/x-www-form-urlencoded" } });
  return resp.data.access_token;
}

async function pollChangedOrders(ifsUrl, token, sinceTimestamp) {
  // OData query with date filter for polling fallback
  const projection = "CustomerOrderHandling";
  const url = `${ifsUrl}/main/ifsapplications/projection/v1/${projection}.svc/CustomerOrderSet`;
  const filter = `Objversion gt '${sinceTimestamp}'`;

  const resp = await axios.get(url, {
    headers: {
      Authorization: `Bearer ${token}`,
      Accept: "application/json",
    },
    params: { $filter: filter, $top: 100 },
  });

  return resp.data.value || [];
}

// Usage:
// const token = await getIfsToken(IFS_URL, CLIENT_ID, CLIENT_SECRET);
// const changes = await pollChangedOrders(IFS_URL, token, "2026-03-03T00:00:00Z");
// console.log(`Found ${changes.length} changed orders`);
```

### cURL: Test IFS Cloud OData connectivity and start a workflow

```bash
# Input:  IFS Cloud URL, client credentials
# Output: OAuth token, OData query result, workflow instance

# Step 1: Get OAuth token from IFS IAM
TOKEN=$(curl -s -X POST \
  "https://yourifs.cloud/auth/realms/ifs/protocol/openid-connect/token" \
  -d "grant_type=client_credentials" \
  -d "client_id=YOUR_CLIENT_ID" \
  -d "client_secret=YOUR_CLIENT_SECRET" \
  | python3 -c "import sys,json;print(json.load(sys.stdin)['access_token'])")

echo "Token obtained: ${TOKEN:0:20}..."

# Step 2: Query an OData projection to verify connectivity
curl -s "https://yourifs.cloud/main/ifsapplications/projection/v1/CustomerOrderHandling.svc/CustomerOrderSet?\$top=3" \
  -H "Authorization: Bearer $TOKEN" \
  -H "Accept: application/json" | python3 -m json.tool

# Step 3: List available workflow process definitions
curl -s "https://yourifs.cloud/main/ifsapplications/projection/engine-rest/process-definition" \
  -H "Authorization: Bearer $TOKEN" \
  -H "Accept: application/json" | python3 -m json.tool

# Step 4: Start a workflow instance
curl -X POST \
  "https://yourifs.cloud/main/ifsapplications/projection/engine-rest/process-definition/key/MyWorkflow/start" \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"withVariablesInReturn": true, "variables": {"testVar": {"value": "hello", "type": "String"}}}'
```

## Data Mapping

### Event Parameter Mapping Reference

| IFS Event Parameter | External Webhook Field | Type | Transform | Gotcha |
|---|---|---|---|---|
| `NEW:ORDER_NO` | `order_number` | String | Direct | Format includes prefix (e.g., "CO-12345") [src1] |
| `NEW:ORDER_STATUS` | `status` | String (enum) | Map to external status codes | IFS uses internal status codes — map to target system values [src1] |
| `OLD:ORDER_STATUS` | `previous_status` | String (enum) | Map to external status codes | Only available in Modify events [src1] |
| `&EVENT_DATETIME` | `event_timestamp` | DateTime | ISO 8601 conversion | Time zone depends on IFS server configuration [src3] |
| `#USER_IDENTITY` | `changed_by` | String | Direct | IFS user ID, not display name [src3] |
| `#USER_MAIL_ADDRESS` | `user_email` | String | Direct | May be empty if user has no email configured [src3] |
| `&ROWKEY` | `record_key` | String (GUID) | Direct | Enables deep linking back to IFS record [src3] |
| LOB attachments | N/A | Binary | Not directly available | LOBs and special data types are excluded from event parameters [src1] |

### Data Type Gotchas

- **Event datetime is server-local**: The `&EVENT_DATETIME` parameter uses the IFS application server's time zone, not UTC. If integrating across time zones, convert explicitly in the receiving system. [src3]
- **Numeric precision varies by entity**: Amount and quantity fields may have different decimal precision depending on the entity and IFS configuration. Do not assume a fixed number of decimal places. [src1]
- **NULL values in substitution fields**: If an attribute value is NULL, the substitution field resolves to an empty string — not the literal text "NULL" or a JSON null. Handle empty strings as potential NULLs in downstream processing. [src1, src3]
- **ROWKEY is essential for deep linking**: The `&ROWKEY` parameter provides a unique record identifier that can be used in IFS URL navigation (Tasks and emails). Always include it in outbound event payloads for traceability. [src3]

## Error Handling & Failure Points

### Common Error Scenarios

| Scenario | Symptom | Cause | Resolution |
|---|---|---|---|
| Execute Online SQL failure | User's business transaction rolls back with generic error | SQL syntax error or constraint violation in event action | Test SQL in isolated session first; wrap in exception handler within PL/SQL block [src1] |
| REST Call timeout | Event fires but external system never receives payload | Target endpoint slow or unreachable | Implement health check on target; consider Workflow with retry instead [src2] |
| Custom event performance hit | Slow insert/update operations on affected table | Database trigger overhead on high-volume table | Review trigger necessity; consider Application Message (async) instead [src1, src3] |
| OAuth token expired in event action | REST Call returns 401 silently | Static Bearer Token configured in event action has expired | Use Workflow with OAuth 2.0 delegate for auto-refresh; avoid static tokens [src5] |
| Workflow fails to start | Event fires but no workflow instance created | Process definition key mismatch or workflow not deployed | Verify process key in IFS Workflow Monitor; redeploy workflow [src4] |
| Condition evaluation error | Event action never fires despite matching data | Incorrect substitution field syntax or data type mismatch in condition | Test conditions with known data; verify attribute names match exactly [src1] |

[src1, src2, src4, src5]

### Failure Points in Production

- **Execute Online SQL cascading rollback**: An event action with Execute Online SQL that violates a constraint rolls back not just the SQL but the entire triggering transaction. The user sees "Error executing request" with no indication the event action caused it. Fix: `Wrap all Execute Online SQL in BEGIN...EXCEPTION...END blocks. Log errors to a custom error table instead of raising exceptions.` [src1]
- **REST Call silent failure during target downtime**: When the external webhook endpoint is down, the REST Call event action fails silently. No retry, no dead letter queue, no notification. Events that fire during the outage window are permanently lost. Fix: `Implement a heartbeat/health check. Use polling with OData date filters as a reconciliation fallback. For critical events, use Workflow with retry logic instead of direct REST Call.` [src2]
- **Custom event trigger accumulation**: Over time, teams add custom events without removing obsolete ones. Each enabled custom event creates a database trigger that fires on every DML operation on that table, regardless of conditions (conditions are evaluated after the trigger fires). Fix: `Audit custom events quarterly. Disable events that are no longer needed. Prefer system-defined events when available.` [src1, src3]
- **Workflow variable type mismatch**: Passing a numeric IFS event parameter to a String-typed workflow variable (or vice versa) causes the workflow to fail at start. The event action reports success, but no workflow instance is created. Fix: `Explicitly declare variable types in both the event action mapping and the workflow definition. Test type compatibility before production deployment.` [src4]

## Anti-Patterns

### Wrong: Using Execute Online SQL for external integration

```sql
-- BAD — this runs in the triggering transaction; if the HTTP call
-- or external DB link fails, the user's order placement rolls back
BEGIN
  send_http_request('https://external.com/api', :NEW:ORDER_NO);
  INSERT INTO external_db_link.orders VALUES (:NEW:ORDER_NO, :NEW:STATUS);
END;
```

### Correct: Use REST Call event action or Workflow for external calls

```plaintext
-- GOOD — REST Call event action fires within the transaction but
-- does not block on failure. For guaranteed delivery, use Workflow:
Event Action Type: REST Call
URL: https://external.com/api/webhook
Method: POST
Body: {"order_no": "NEW:ORDER_NO", "status": "NEW:ORDER_STATUS"}

-- OR for guaranteed delivery with retry:
Event Action Type: Workflow
Process Key: ExternalOrderSync
Variables: orderNo=NEW:ORDER_NO, status=NEW:ORDER_STATUS
```

### Wrong: Creating custom events for entities that have system-defined events

```plaintext
-- BAD — creates a redundant database trigger that fires alongside
-- the existing system-defined event, doubling the overhead
Custom Event: CustomerOrder_Modify_After
Trigger: After Modify on CustomerOrder
(System-defined event already exists for CustomerOrder status changes)
```

### Correct: Register actions on existing system-defined events

```plaintext
-- GOOD — attach your action to the existing system-defined event
-- No additional trigger overhead; IFS optimizes system events
Event: CustomerOrder.StatusChanged (system-defined)
Action Type: REST Call
Condition: NEW:ORDER_STATUS = 'Released'
```

### Wrong: Relying solely on REST Call event actions for mission-critical data sync

```plaintext
-- BAD — no retry, no delivery confirmation, no dead letter queue
Event: InventoryTransaction.New
Action: REST Call to warehouse management system
(If WMS is down for 10 minutes, all inventory events during that window are lost)
```

### Correct: Use Workflow with retry for critical integrations, REST Call polling as fallback

```plaintext
-- GOOD — Workflow handles retry; polling catches any gaps
Event: InventoryTransaction.New
Action: Start Workflow "InventorySyncWorkflow"
  - Service Task: REST Call to WMS (with 3 retry attempts, exponential backoff)
  - Error Handler: Log to error table, send alert email
  - Compensation: Mark record for manual review

PLUS: Scheduled polling job via OData API
  - Every 15 minutes, query InventoryTransaction where Objversion > lastSyncTimestamp
  - Reconcile any records missed by event-driven path
```

## Common Pitfalls

- **Assuming events fire after transaction commit**: Custom events with "After" timing fire after the business logic completes but still within the database transaction. If a subsequent operation in the same transaction fails, the event action's side effects (e.g., REST call already sent) cannot be undone. Fix: `For external notifications, use Application Message (async, fires after commit) or design the receiving system to handle duplicate/orphan events.` [src1]
- **Overloading events with complex Execute Online SQL**: Complex SQL in event actions is tempting for quick automation, but it increases transaction lock time and makes debugging nearly impossible. Fix: `Keep Execute Online SQL to simple validations or flag-setting. Move complex logic to Workflows where it can be monitored, retried, and debugged.` [src1]
- **Not testing event actions in a representative environment**: Event actions that work in a test environment with low data volume may cause performance issues in production due to trigger overhead on high-volume tables. Fix: `Load-test custom events with production-representative data volumes before go-live. Monitor database trigger execution times.` [src1, src3]
- **Hardcoding URLs in REST Call event actions**: When migrating between environments (dev, test, prod), REST Call URLs must be updated manually. Missing one causes silent event delivery failures. Fix: `Use a configuration table or IFS System Parameter to store target URLs. Reference the parameter in event action configuration.` [src2]
- **Ignoring the difference between Before and After event timing**: "Before" events can modify or block the triggering transaction (e.g., display error messages that roll back). "After" events cannot block but have access to the final state. Using the wrong timing causes either unwanted transaction blocking or missing data. Fix: `Use "After" for notifications and external integrations. Use "Before" only for validations that should prevent the transaction.` [src1]
- **Not monitoring Workflow engine health**: Workflows triggered by event actions depend on the Camunda engine being operational. If the engine is overloaded or down, events fire but no workflow instances are created. Fix: `Set up monitoring on the Camunda REST API (/engine-rest/process-instance). Alert when workflow instance creation latency exceeds thresholds.` [src4]

## Diagnostic Commands

```bash
# Test IFS Cloud OAuth authentication
curl -s -X POST "https://yourifs.cloud/auth/realms/ifs/protocol/openid-connect/token" \
  -d "grant_type=client_credentials&client_id=CLIENT_ID&client_secret=SECRET" \
  | python3 -c "import sys,json;d=json.load(sys.stdin);print('Auth OK' if 'access_token' in d else f'Error: {d}')"

# Verify OData projection accessibility
curl -s "https://yourifs.cloud/main/ifsapplications/projection/v1/CustomerOrderHandling.svc/\$metadata" \
  -H "Authorization: Bearer $TOKEN" \
  -H "Accept: application/xml" | head -20

# List deployed workflow process definitions
curl -s "https://yourifs.cloud/main/ifsapplications/projection/engine-rest/process-definition" \
  -H "Authorization: Bearer $TOKEN" | python3 -c "import sys,json;[print(p['key'],p['name']) for p in json.load(sys.stdin)]"

# Check workflow instance history (last 10)
curl -s "https://yourifs.cloud/main/ifsapplications/projection/engine-rest/history/process-instance?sortBy=startTime&sortOrder=desc&maxResults=10" \
  -H "Authorization: Bearer $TOKEN" | python3 -m json.tool

# Monitor active workflow instances (check for stuck processes)
curl -s "https://yourifs.cloud/main/ifsapplications/projection/engine-rest/process-instance?active=true" \
  -H "Authorization: Bearer $TOKEN" | python3 -c "import sys,json;d=json.load(sys.stdin);print(f'{len(d)} active instances')"
```

## Version History & Compatibility

| IFS Release | Date | Status | Event Framework Changes | Migration Notes |
|---|---|---|---|---|
| 25R1 | 2025-06 | Current | Enhanced workflow integration, improved event monitoring | Workflow process definitions may need redeployment |
| 24R2 | 2024-10 | Supported | REST Call event action improvements, OAuth 2.0 in Workflow delegate | Verify REST Call configurations after upgrade [src5] |
| 23R1 | 2023-06 | Supported | Custom command workflow triggering added (3rd trigger path) | New capability; no breaking changes [src4, src7] |
| 22R1 | 2022-06 | Legacy | Workflow (Camunda) engine integration with events | Minimum version for Workflow event actions |
| 21R2 | 2021-10 | Legacy | Streams Message event action type introduced | — |
| Foundation1 (IFS Apps 10) | Pre-2021 | Legacy | Original ECA framework — 5 action types (no REST Call, no Workflow) | REST Call and Workflow actions require IFS Cloud upgrade [src1, src3] |

[src1, src3, src4]

### Deprecation Policy

IFS follows a continuous release model with two major releases per year (R1 and R2). The event framework is backward-compatible — events and actions configured in earlier releases continue to work after upgrade. IFS provides at least one major release cycle (6 months) notice before deprecating event framework features. The transition from IFS Applications 10 to IFS Cloud added REST Call and Workflow action types; no legacy action types have been removed. [src1, src3]

## When to Use / When Not to Use

| Use When | Don't Use When | Use Instead |
|---|---|---|
| Need real-time outbound notifications when IFS entities change | Need to poll IFS for changed records on a schedule | OData REST API with date filter polling |
| Want webhook-style integration without custom server-side code | Need guaranteed exactly-once delivery of events | Message broker (IFS Connect + MQ) or middleware (MuleSoft, Boomi) |
| Triggering multi-step processes (approvals, multi-system sync) | Need simple CRUD operations on IFS data | OData REST API direct calls |
| Sending conditional email alerts on business entity changes | Need complex data transformation before sending | IFS Connect with XSLT transformers |
| Need to validate/block transactions before they commit (Before events) | Need to process high-volume streaming data (>10K events/minute) | Dedicated event streaming platform (Kafka, RabbitMQ) with OData polling |

## Important Caveats

- The IFS Event Framework is tightly coupled to the Oracle database layer. Custom events create database triggers that add overhead to every DML operation on the affected table, regardless of whether conditions match. Performance testing with production data volumes is essential before enabling custom events on high-transaction tables. [src1, src3]
- REST Call event actions are fire-and-forget with no built-in retry or delivery tracking. For mission-critical integrations, use Workflow event actions with explicit retry logic, or implement a reconciliation mechanism using OData API polling. [src2, src5]
- The IFS REST Call Workflow delegate (`IfsHttpConnectionDelegate`) has known limitations: no advanced authentication methods, limited response parsing, and no built-in logging. Complex outbound integrations may require a dedicated middleware layer. [src5]
- Event action configurations are environment-specific. When promoting from development to production, all event action configurations (URLs, credentials, conditions) must be manually verified and updated. There is no automated environment-aware configuration mechanism. [src1, src2]
- IFS Cloud's authentication and authorization model has changed significantly from IFS Applications 10. Legacy integrations using direct database connections or basic auth must be migrated to OAuth 2.0 via IFS IAM when upgrading to IFS Cloud. [src6]

## Related Units

- [IFS Cloud OData REST API for CRUD and projection access](/business/erp-integration/ifs-odata-api/2026)
- [IFS Cloud Workflows (Camunda BPMN) for process orchestration](/business/erp-integration/ifs-workflow-engine/2026)
- [IFS Connect service bus for message-based integration](/business/erp-integration/ifs-connect-middleware/2026)
- [Real-time sync playbook between IFS Cloud and external systems](/business/erp-integration/ifs-external-system-sync/2026)
