---
# === IDENTITY ===
id: business/erp-integration/ifs-aurena-extensibility/2026
canonical_question: "How does IFS Aurena extensibility work for customization and integration?"
aliases:
  - "IFS Cloud Aurena custom pages, projections, and extension layers"
  - "How to extend IFS Aurena with custom projections and client pages"
  - "IFS Aurena @Override and @Overtake customization annotations"
  - "IFS Cloud OData projection extensibility and REST API integration"
entity_type: erp_integration
domain: business > erp-integration > ifs-aurena-extensibility
region: global
jurisdiction: global
temporal_scope: 2024-2026

# === SYSTEM PROFILE ===
systems:
  - name: "IFS Cloud (Aurena)"
    vendor: "IFS"
    version: "IFS Cloud 24R2"
    edition: "All editions"
    deployment: "cloud"
    api_surface: "OData v4 (Projections)"

# === 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: "24R1 — external REST API calls from workflows introduced; 24R2 — enhanced OAuth in IFS REST Task"
  next_review: 2026-08-30
  change_sensitivity: high

# === CONSTRAINTS ===
constraints:
  - "Customizations must use the Cust layer (-Cust suffix files) — modifying base layer files is unsupported and will be overwritten on upgrade"
  - "Commands in .client files are atomic and cannot use @Override — they must be fully rewritten using @Overtake"
  - "Projections exposed via /main/ require OAuth 2.0 / OpenID Connect — Basic Auth is only available for Integration-category projections on /int/ path"
  - "Custom projections and extensions are deployment-specific — they must be packaged as IFS Cloud components and redeployed across environments"
  - "Lobby elements cannot be created in Aurena — lobby design and element configuration must be done through Enterprise Explorer (EE)"
  - "@Overtake replaces the entire original definition — partial overrides are not possible for overtaken elements"

# === SKIP CONDITIONS ===
skip_this_unit_if:
  - condition: "User needs IFS REST API rate limits and OData query patterns only"
    use_instead: "business/erp-integration/ifs-cloud-rest-api/2026"
  - condition: "User needs IFS-to-Salesforce or IFS-to-SAP integration playbook"
    use_instead: "business/erp-integration/ifs-salesforce-integration/2026"
  - condition: "User needs IFS legacy (Applications 10 / EE) customization, not Aurena"
    use_instead: "N/A — see IFS Applications 10 customization documentation"

# === 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, business events)"
      - "UI extensibility (custom pages, projections, lobbies)"
  - 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 from IFS Cloud)"
      - "bidirectional sync"

# === DISTRIBUTION ===
canonical_source: "https://knowledgelib.io/business/erp-integration/ifs-aurena-extensibility/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-cloud-rest-api/2026"
      label: "IFS Cloud OData/REST API capabilities and rate limits"
  solves:
    - id: "business/erp-integration/ifs-middleware-integration/2026"
      label: "IFS Cloud middleware integration playbooks"
  alternative_to:
    - id: "business/erp-integration/sap-extensibility/2026"
      label: "SAP S/4HANA extensibility model for comparison"
  often_confused_with:
    - id: "business/erp-integration/ifs-ee-customization/2026"
      label: "IFS Enterprise Explorer (legacy) customization — different framework from Aurena"

# === SOURCES ===
sources:
  - id: src1
    title: "IFS Aurena Overview — Technical Documentation"
    author: IFS
    url: https://docs.ifs.com/techdocs/Foundation1/050_development/022_user_interface/030_aurena_dev/010_aurena_overview/
    type: official_docs
    published: 2024-01-15
    reliability: authoritative
  - id: src2
    title: "Create a new IFS Aurena Customization — Technical Documentation"
    author: IFS
    url: https://docs.ifs.com/techdocs/24r2/060_development/022_user_interface/030_aurena_dev/120_handling_customizations/020_create_new_customizations/
    type: official_docs
    published: 2024-10-01
    reliability: authoritative
  - id: src3
    title: "Layered Application Architecture — Technical Documentation"
    author: IFS
    url: https://docs.ifs.com/techdocs/21r2/010_overview/100_architecture/010_laa_overview/
    type: official_docs
    published: 2023-06-15
    reliability: authoritative
  - id: src4
    title: "Inbound Integrations to IFS Using RESTful APIs"
    author: IFS
    url: https://docs.ifs.com/techdocs/22r1/040_tailoring/300_extensibility/600_integration/040_rest_apis/010_inbound_rest/
    type: official_docs
    published: 2023-09-01
    reliability: authoritative
  - id: src5
    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-03-20
    reliability: moderate_high
  - id: src6
    title: "IFS Authentication Flow with OAuth and OpenID Connect"
    author: DSJ's Blog
    url: https://dsj23.me/2021/01/08/ifs-authentication-flow-with-oauth-and-openid-connect/
    type: technical_blog
    published: 2021-01-08
    reliability: moderate_high
  - id: src7
    title: "Customization Best Practices — Technical Documentation"
    author: IFS
    url: https://docs.ifs.com/techdocs/21r2/060_tailoring/400_customization/010_customization_best_practices/
    type: official_docs
    published: 2023-06-15
    reliability: authoritative
  - id: src8
    title: "Integration and Extensibility — IFS Cloud 24R2 Technical Documentation"
    author: IFS
    url: https://docs.ifs.com/techdocs/24r2/040_tailoring/300_extensibility/
    type: official_docs
    published: 2024-10-01
    reliability: authoritative
---

# IFS Aurena Extensibility: Custom Pages, Projections, and Integration Guide

## TL;DR

- **Bottom line**: IFS Aurena extensibility is built on a layered architecture — the `.client` file defines the UI, the `.projection` file defines the data/API layer, and customizations live in a separate Cust layer using `@Override` (merge changes) or `@Overtake` (replace entirely) annotations. Projections double as OData v4 REST endpoints for external integration.
- **Key limit**: Commands in `.client` files are atomic — they cannot be partially overridden with `@Override` and must be fully rewritten with `@Overtake`. Lobby element creation still requires Enterprise Explorer, not Aurena.
- **Watch out for**: Mixing up `@Override` and `@Overtake` — `@Override` merges your changes with the base layer, while `@Overtake` completely replaces the original definition. Using `@Overtake` when `@Override` would suffice makes upgrades harder. [src2]
- **Best for**: Extending IFS Cloud with custom pages, custom projections (that also serve as REST/OData APIs), lobby dashboards, and non-intrusive customizations that survive upgrades. [src1, src3]
- **Authentication**: OAuth 2.0 / OpenID Connect via IFS IAM for `/main/` Aurena projections; Basic Auth available only for Integration-category projections on the `/int/` path. [src5, src6]

## System Profile

IFS Cloud is a cloud-native ERP platform built on a component-based architecture. The Aurena client is the modern web-based UI (replacing the legacy Enterprise Explorer / Java-based client), built using a declarative domain-specific language called Marble. Aurena uses a clear separation between the client layer (UI definition in `.client` files) and the projection layer (data/API definition in `.projection` files). The underlying architecture generates two deployable packages from these models: the `_CPI` package (client page definition) and the `_SVC` package (projection/service logic). The projection services are exposed as OData v4 endpoints, making every Aurena projection inherently a REST API. This card covers the extensibility model for IFS Cloud 24R2 across all editions. It does not cover the legacy Enterprise Explorer (IFS Applications 10) customization framework or the IFS Connect middleware. [src1, src3]

| Property | Value |
|---|---|
| **Vendor** | IFS |
| **System** | IFS Cloud 24R2 (Aurena client) |
| **API Surface** | OData v4 (Projections as REST endpoints) |
| **Current API Version** | 24R2 (November 2024 release) |
| **Editions Covered** | All IFS Cloud editions |
| **Deployment** | Cloud (SaaS) / Managed Cloud |
| **API Docs URL** | [IFS Technical Documentation — Extensibility](https://docs.ifs.com/techdocs/24r2/040_tailoring/300_extensibility/) |
| **Status** | GA |

## API Surfaces & Capabilities

IFS Aurena extensibility spans both UI customization and API integration. Every projection defined in Marble is automatically exposed as an OData v4 service endpoint, which means UI extensibility and API extensibility are the same thing. [src1, src4]

| API Surface | Protocol | Best For | Max Records/Request | Rate Limit | Real-time? | Bulk? |
|---|---|---|---|---|---|---|
| OData v4 Projections (Main) | HTTPS/JSON OData | Aurena pages + external OAuth integrations | Configurable via `$top` | Server-managed (no published hard limit) | Yes | Paged |
| OData v4 Projections (Integration) | HTTPS/JSON OData | Middleware / iPaaS integrations (Basic Auth) | Configurable via `$top` | Server-managed | Yes | Paged |
| Custom Projections | HTTPS/JSON OData | New business entities, custom logic | Same as standard projections | Shared with projection pool | Yes | Paged |
| Projection Actions | HTTPS/JSON POST | Business operations (approve, release) | N/A (action-based) | Shared | Yes | N/A |
| Push Notifications / Business Events | HTTP callbacks | Real-time outbound event detection | N/A | N/A | Yes | N/A |
| IFS REST Task (Workflows) | HTTPS/JSON | Calling external REST APIs from IFS workflows | N/A | Per-workflow | Yes | N/A |

[src1, src4, src8]

## Rate Limits & Quotas

IFS Cloud does not publish hard numeric API rate limits in the same way as Salesforce or NetSuite. Instead, rate management is handled at the infrastructure level through server-side throttling, connection pooling, and tenant isolation.

### Per-Request Limits

| Limit Type | Value | Applies To | Notes |
|---|---|---|---|
| Max records per query page | Configurable via `$top` parameter | All OData projections | Default page size varies by projection; use `$top` and `$skip` for pagination [src4] |
| Max `$expand` depth | Limited (implementation-dependent) | OData queries | Deep nesting of entity expansions may hit server limits or timeout [src4] |
| Max request body size | Server-configured (typically 10-50 MB) | POST/PUT operations | Depends on IFS Cloud deployment configuration |
| Concurrent OData connections | Deployment-dependent | Per tenant | Managed by IFS Cloud infrastructure; consult IFS support for tenant-specific limits |

[src4, src5]

### Rolling / Daily Limits

| Limit Type | Value | Window | Edition Differences |
|---|---|---|---|
| API request throughput | Server-managed (no published hard limit) | Continuous | IFS uses infrastructure-level throttling rather than per-API-call counting [src5] |
| Concurrent user sessions | License-dependent | Per deployment | Check IFS Cloud licensing terms for concurrent user limits |
| Workflow REST Task calls | Per-workflow frequency limits | Per execution | Configurable in workflow designer; new in 24R1 [src8] |
| Integration projection sessions | Deployment-dependent | Per tenant | Basic Auth sessions on /int/ path may have separate connection pooling |

[src5, src8]

## Authentication

IFS Cloud uses IFS IAM (Identity and Access Manager) as its OAuth 2.0 authorization server. The authentication method depends on whether you access projections through the Main application path or the Integration path. [src5, src6]

| Flow | Use When | Token Lifetime | Refresh? | Notes |
|---|---|---|---|---|
| OAuth 2.0 / OpenID Connect | All Aurena `/main/` projections | Configurable in IFS IAM | Yes | Required for standard Aurena projections; uses authorization code flow for interactive, client credentials for service-to-service [src5, src6] |
| Basic Auth (Integration category) | Middleware / iPaaS tools via `/int/` path | Session-based | No | Only available for projections with category set to "Integration" in API Explorer [src5] |
| Client Credentials (OAuth 2.0) | Server-to-server automation | Configurable | Yes | Register application in IFS IAM; recommended for unattended integrations [src6] |
| Authorization Code (OAuth 2.0) | User-context interactive applications | Configurable | Yes | Redirect-based flow; user authenticates via IFS login page [src6] |

[src5, src6]

### Authentication Gotchas

- **Main vs Integration path**: Projections on `/main/ifsapplications/projection/v1/` require OAuth 2.0. If your middleware tool only supports Basic Auth, you must change the projection category to "Integration" in the API Explorer, which moves it to the `/int/` path. This is a per-projection configuration change, not a global setting. [src5]
- **IFS IAM token scopes**: Tokens issued by IFS IAM carry scopes tied to the user's IFS permission sets. A valid OAuth token with insufficient permissions returns 403, not 401 — the token is valid but the user lacks access to the projection. [src6]
- **CORS and cookie handling**: Aurena's browser-based client uses cookies for session management alongside OAuth tokens. External API consumers should use Bearer tokens, not browser cookies. [src5]
- **Integration category exposes Basic Auth attack surface**: Enabling Basic Auth on a projection removes the OAuth layer. Only set a projection to Integration category when the consuming system cannot support OAuth, and restrict network access to known IP ranges. [src5]

## Constraints

- **Cust layer is mandatory for customizations**: All customizations must use files with the `-Cust` suffix in the Cust layer. Modifying base layer files directly is unsupported — IFS upgrades overwrite base layer files, destroying any changes. [src2, src7]
- **Commands cannot use @Override**: Commands in `.client` files are atomic units. You cannot partially modify a command — you must `@Overtake` the entire command definition and rewrite it completely. [src2]
- **Lobby creation requires Enterprise Explorer**: While Aurena displays lobbies, the lobby designer (creating elements, data sources, KPI metrics) still requires Enterprise Explorer (EE). Lobby elements configured in EE appear in Aurena but cannot be created or edited through Aurena. [src1]
- **Projection extensions are component-scoped**: Custom projections and extensions belong to a specific IFS Cloud component. Moving them between environments requires packaging them as part of a customization deployment, not simple file copying. [src2, src3]
- **Code generation merges layers at deploy time**: The Marble code generator merges base layer + extension layer + Cust layer during deployment. Conflicts between layers (especially overlapping `@Overtake` annotations) can cause deployment failures. [src3]
- **PL/SQL backing code required for custom actions**: While the projection model is defined in Marble DSL, any custom action or function in a projection requires a backing `.plsvc` (PL/SQL) file implementing the business logic. The Marble definition alone is not sufficient. [src1, src2]

## Integration Pattern Decision Tree

```
START -- User needs to extend or integrate with IFS Cloud (Aurena)
|-- What type of extensibility?
|   |-- UI Customization (change existing pages)
|   |   |-- Need to add fields to existing page?
|   |   |   |-- YES --> @Override in .client-Cust + add attribute in .projection-Cust [src2]
|   |   |   |-- Also need the field in the API? --> It's automatic — projection changes expose via OData
|   |   |-- Need to change page behavior (commands, validation)?
|   |   |   |-- YES --> @Overtake the command in .client-Cust [src2]
|   |   |   |-- NO --> @Override for layout changes only
|   |   |-- Need a completely new page?
|   |       |-- YES --> Create new .client + .projection + .plsvc in Cust layer [src2]
|   |       |-- Register in navigator via Solution Manager
|   |-- API / Data Integration (external systems)
|   |   |-- Read data from IFS?
|   |   |   |-- Use existing projection --> Expose as OData via API Explorer [src4]
|   |   |   |-- Need custom data shape --> Create custom projection with custom entity [src4]
|   |   |-- Write data to IFS?
|   |   |   |-- Standard CRUD --> POST/PUT to projection OData endpoint [src4]
|   |   |   |-- Business action (approve, release) --> POST to projection action endpoint [src4]
|   |   |-- Authentication?
|   |       |-- OAuth 2.0 capable --> Use /main/ path (standard) [src5]
|   |       |-- Basic Auth only --> Set projection to Integration category, use /int/ path [src5]
|   |-- Dashboard / Lobby
|   |   |-- Use Enterprise Explorer lobby designer [src1]
|   |   |-- Configure data sources (SQL query or Information Source)
|   |   |-- Set element types (chart, list, KPI) and navigation
|   |   |-- Lobby appears automatically in Aurena after configuration
|   |-- Workflow Integration (24R1+)
|       |-- Need to call external REST API from IFS?
|       |   |-- YES --> Use IFS REST Task in workflow designer [src8]
|       |   |-- Configure URL, OAuth, and payload in IFS REST Task Configurations
|       |-- Need event-driven outbound notifications?
|           |-- YES --> Use Business Events + push notification subscriptions
|           |-- NO --> Polling via OData with $filter on modification timestamps
|-- Which customization layer?
|   |-- Cust layer (-Cust suffix) --> Customer-specific changes [src2, src7]
|   |-- Ext layer (-Ext suffix) --> ISV/partner extensions (if applicable) [src3]
|   |-- Base layer --> Never modify (IFS-owned) [src7]
|-- Deployment?
    |-- Package as IFS Cloud component
    |-- Deploy via IFS Cloud lifecycle management
    |-- Test in sandbox first -- customization conflicts possible at merge time [src3]
```

## Quick Reference

| Operation | Method | Endpoint Pattern | Payload | Notes |
|---|---|---|---|---|
| Query records | GET | `/main/ifsapplications/projection/v1/{ProjectionName}.svc/{EntitySet}` | N/A | OData v4 with $filter, $select, $expand, $top, $skip [src4] |
| Get single record | GET | `/main/ifsapplications/projection/v1/{ProjectionName}.svc/{EntitySet}(keys)` | N/A | Key fields in parentheses [src4] |
| Create record | POST | `/main/ifsapplications/projection/v1/{ProjectionName}.svc/{EntitySet}` | JSON | Standard OData POST [src4] |
| Update record | PATCH | `/main/ifsapplications/projection/v1/{ProjectionName}.svc/{EntitySet}(keys)` | JSON | Partial update supported via PATCH [src4] |
| Delete record | DELETE | `/main/ifsapplications/projection/v1/{ProjectionName}.svc/{EntitySet}(keys)` | N/A | Not all entities support delete [src4] |
| Execute action | POST | `/main/ifsapplications/projection/v1/{ProjectionName}.svc/{ActionName}` | JSON params | Actions defined in projection [src4] |
| Integration path (Basic Auth) | GET/POST | `/int/ifsapplications/projection/v1/{ProjectionName}.svc/{EntitySet}` | JSON/N/A | Only for Integration-category projections [src5] |
| API Explorer | Browser | Solution Manager > Integration > API Explorer | N/A | Browse all projections, enable for integration, test endpoints [src4] |
| Custom page registration | N/A | Solution Manager > Navigator | N/A | Register custom .client pages in navigator tree [src1] |

## Step-by-Step Integration Guide

### 1. Explore available projections in API Explorer

Navigate to Solution Manager > Integration > API Explorer. This shows all projections available in your IFS Cloud instance, organized by component and category. Each projection lists its entity sets, actions, and functions. You can test OData queries directly in the Explorer and enable projections for integration (Basic Auth) access. [src4]

```plaintext
Steps in IFS Cloud:
1. Navigate to Solution Manager > Integration > API Explorer
2. Browse or search for the projection you need (e.g., "CustomerHandling")
3. Click the projection to see entity sets, actions, and functions
4. Note the projection name — this forms the OData endpoint URL
5. To enable Basic Auth: click "Enable for Integration" on the projection
6. Test with the built-in OData query tool
```

**Verify**: The projection appears in the API Explorer with its entity sets listed. If enabling for integration, confirm the projection is accessible via the `/int/` path.

### 2. Authenticate and obtain OAuth access token

Register your application in IFS IAM and obtain OAuth 2.0 tokens. For server-to-server integrations, use the client credentials flow. [src5, src6]

```bash
# Input:  IFS Cloud instance URL, client_id, client_secret from IFS IAM
# Output: OAuth 2.0 access token

# Discover OAuth endpoints (OpenID Connect discovery)
curl -s "https://yourinstance.ifs.cloud/.well-known/openid-configuration" | python3 -m json.tool

# Obtain access token using client credentials flow
curl -X POST "https://yourinstance.ifs.cloud/auth/realms/ifs/protocol/openid-connect/token" \
  -H "Content-Type: application/x-www-form-urlencoded" \
  -d "grant_type=client_credentials" \
  -d "client_id=YOUR_CLIENT_ID" \
  -d "client_secret=YOUR_CLIENT_SECRET" \
  -d "scope=openid"

# Response:
# {
#   "access_token": "eyJ...",
#   "expires_in": 300,
#   "token_type": "Bearer"
# }
```

**Verify**: The response contains an `access_token` field. Test it against a known projection endpoint.

### 3. Query data via OData projection endpoint

Use standard OData v4 query syntax against the projection endpoint. The projection name maps directly to the `.projection` file name in IFS Cloud. [src4]

```bash
# Input:  Access token, projection name, entity set name
# Output: JSON array of records

# Query customer orders with filtering and pagination
curl -X GET "https://yourinstance.ifs.cloud/main/ifsapplications/projection/v1/CustomerOrderHandling.svc/CustomerOrderSet?\$filter=State eq 'Planned'&\$top=50&\$skip=0&\$select=OrderNo,CustomerNo,WantedDeliveryDate" \
  -H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
  -H "Accept: application/json"

# Using Basic Auth on Integration path
curl -X GET "https://yourinstance.ifs.cloud/int/ifsapplications/projection/v1/CustomerOrderHandling.svc/CustomerOrderSet?\$top=10" \
  -u "username:password" \
  -H "Accept: application/json"
```

**Verify**: Response contains an `@odata.context` field and a `value` array with matching records.

### 4. Create a custom projection for a new data shape

When existing projections do not expose the data shape you need, create a custom projection in the Cust layer. This requires IFS Developer Studio. [src1, src2]

```plaintext
-- File: YourComponent-Cust.projection (Marble DSL)
projection MyCustomIntegrationHandling;
component YourComponent;
layer Cust;
description "Custom projection for external integration";

-- Define the entity set
entityset MyCustomEntitySet for MyCustomEntity;

-- Define the entity with selected attributes
@Override
entity MyCustomEntity {
   attribute OrderNo Text;
   attribute CustomerNo Text;
   attribute TotalAmount Number;
   attribute Status Enumeration(CustomerOrderState);

   -- Custom computed attribute
   attribute FormattedTotal Text {
      fetch = "TO_CHAR(total_amount, '999,999.00')";
   }
}

-- Define a custom action
action ApproveOrder {
   initialcheck none;
   parameter OrderNo Text;
}
```

**Verify**: After deploying via IFS Developer Studio, the projection appears in API Explorer and is queryable via OData.

### 5. Extend an existing Aurena page with custom fields

Use `@Override` in a Cust-layer `.client` file to add fields to existing pages without modifying the base layer. [src2]

```plaintext
-- File: CustomerOrderHandling-Cust.client (Marble DSL)
client CustomerOrderHandlingCust;
component ORDER;
layer Cust;

-- Override the existing page to add a new field group
@Override
page CustomerOrderForm using CustomerOrderSet {
   group CustomFieldsGroup after GeneralGroup {
      label = "Custom Fields";
      field MyCustomField {
         label = "Custom Reference";
         size = Medium;
      }
      field IntegrationStatus {
         label = "Integration Status";
         size = Small;
         editable = [false];
      }
   }
}
```

**Verify**: Navigate to the Customer Order page in Aurena. The new field group appears after the General group with the custom fields visible.

### 6. Implement error handling for OData integration

Parse OData error responses and implement retry logic for transient failures. [src4, src5]

```python
# Input:  IFS Cloud instance URL, OAuth token, projection details
# Output: Successful response or structured error information

import requests
import time

def ifs_odata_request(instance_url, token, projection, entity_set,
                      params=None, max_retries=3):
    """Make an IFS Cloud OData request with retry logic."""
    url = (f"{instance_url}/main/ifsapplications/projection/v1/"
           f"{projection}.svc/{entity_set}")
    headers = {
        "Authorization": f"Bearer {token}",
        "Accept": "application/json",
        "Content-Type": "application/json"
    }

    for attempt in range(max_retries):
        try:
            response = requests.get(url, headers=headers, params=params,
                                    timeout=30)

            if response.status_code == 200:
                data = response.json()
                return data.get("value", [])

            if response.status_code == 401:
                raise Exception(
                    "Authentication failed — token expired or insufficient "
                    "permissions. Check IFS IAM scopes and user permissions."
                )

            if response.status_code == 403:
                raise Exception(
                    "Forbidden — valid token but user lacks projection "
                    "access. Check IFS permission sets for this projection."
                )

            if response.status_code == 404:
                raise Exception(
                    f"Projection or entity set not found: {projection}/"
                    f"{entity_set}. Verify names in API Explorer."
                )

            if response.status_code in (500, 502, 503):
                wait = min(2 ** attempt * 2, 30)
                print(f"Server error {response.status_code}. "
                      f"Retrying in {wait}s (attempt {attempt + 1})")
                time.sleep(wait)
                continue

            # Parse OData error body
            try:
                error_body = response.json()
                error_msg = (error_body.get("error", {})
                             .get("message", {})
                             .get("value", "Unknown error"))
            except ValueError:
                error_msg = response.text[:500]
            raise Exception(
                f"IFS OData error {response.status_code}: {error_msg}"
            )

        except requests.exceptions.Timeout:
            if attempt < max_retries - 1:
                time.sleep(2 ** attempt)
                continue
            raise Exception("Request timed out after all retries")

    raise Exception("Max retries exceeded")
```

**Verify**: Test with an invalid projection name to confirm error parsing returns a readable message.

## Code Examples

### Python: Query and paginate IFS Cloud OData projection

```python
# Input:  IFS Cloud instance URL, OAuth token
# Output: All customer orders matching filter across all pages

import requests

def get_all_orders(instance_url, token, state="Planned", page_size=100):
    """Paginate through all customer orders matching a state filter."""
    headers = {
        "Authorization": f"Bearer {token}",
        "Accept": "application/json"
    }
    all_orders = []
    skip = 0

    while True:
        url = (
            f"{instance_url}/main/ifsapplications/projection/v1/"
            f"CustomerOrderHandling.svc/CustomerOrderSet"
            f"?$filter=State eq '{state}'"
            f"&$top={page_size}&$skip={skip}"
            f"&$select=OrderNo,CustomerNo,WantedDeliveryDate,TotalAmount"
        )
        resp = requests.get(url, headers=headers, timeout=30)
        resp.raise_for_status()
        data = resp.json()
        records = data.get("value", [])

        if not records:
            break

        all_orders.extend(records)
        if len(records) < page_size:
            break  # Last page
        skip += page_size

    return all_orders

# Usage:
# orders = get_all_orders("https://myinstance.ifs.cloud", token)
# print(f"Total orders: {len(orders)}")
```

### JavaScript/Node.js: Create a record via OData POST

```javascript
// Input:  IFS Cloud instance URL, OAuth token, order data
// Output: Created customer order record or error details

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

async function createCustomerOrder(instanceUrl, token, orderData) {
  const url = `${instanceUrl}/main/ifsapplications/projection/v1/CustomerOrderHandling.svc/CustomerOrderSet`;

  try {
    const response = await axios.post(url, orderData, {
      headers: {
        Authorization: `Bearer ${token}`,
        "Content-Type": "application/json",
        Accept: "application/json",
      },
    });
    console.log("Order created:", response.data.OrderNo);
    return response.data;
  } catch (error) {
    if (error.response?.status === 403) {
      console.error(
        "Forbidden — check IFS permission sets for this projection"
      );
    } else if (error.response?.status === 400) {
      const msg =
        error.response.data?.error?.message?.value || "Validation error";
      console.error("Validation failed:", msg);
    }
    throw error;
  }
}

// Usage:
// createCustomerOrder("https://myinstance.ifs.cloud", token, {
//   CustomerNo: "CUST001",
//   WantedDeliveryDate: "2026-04-15",
//   CurrencyCode: "USD"
// });
```

### cURL: Quick OData connectivity test

```bash
# Input:  IFS Cloud instance URL, OAuth token or Basic Auth credentials
# Output: First 5 records from a standard projection

# Test with OAuth (Main path)
curl -s "https://yourinstance.ifs.cloud/main/ifsapplications/projection/v1/CustomerHandling.svc/CustomerSet?\$top=5" \
  -H "Authorization: Bearer $TOKEN" \
  -H "Accept: application/json" | python3 -m json.tool

# Test with Basic Auth (Integration path)
curl -s "https://yourinstance.ifs.cloud/int/ifsapplications/projection/v1/CustomerHandling.svc/CustomerSet?\$top=5" \
  -u "integration_user:password" \
  -H "Accept: application/json" | python3 -m json.tool

# Test OData metadata
curl -s "https://yourinstance.ifs.cloud/main/ifsapplications/projection/v1/CustomerHandling.svc/\$metadata" \
  -H "Authorization: Bearer $TOKEN" \
  -H "Accept: application/xml"
```

## Data Mapping

### Field Mapping Reference

| IFS Aurena Field | OData Representation | Type | Transform | Gotcha |
|---|---|---|---|---|
| Standard attribute | Direct JSON property | String/Number/Date | None — OData standard | Field names match Marble attribute names, case-sensitive [src4] |
| Enumeration fields | String value | String | Display value in OData, internal code in DB | Filter by display value in OData queries, not internal enum code [src4] |
| Reference fields (LOV) | String (key value) | String | Key value only, not description | Use `$expand` to get reference description attributes [src4] |
| Date fields | ISO 8601 string | DateTimeOffset | `YYYY-MM-DDTHH:MM:SSZ` | Time zone depends on IFS Cloud instance configuration [src4] |
| Computed/virtual fields | Read-only JSON property | Varies | Defined by `fetch` attribute in projection | Cannot be updated via API — they are derived from SQL [src1] |
| Custom fields (Cust layer) | Same as standard | Varies | Exposed automatically if added to projection | Must be added to projection-Cust file to appear in OData [src2] |
| Binary/BLOB fields | Not directly exposed | N/A | Use document attachment APIs | Large binary data requires separate handling [src4] |

### Data Type Gotchas

- **Enumeration values in filters vs display**: IFS Cloud stores enumerations as internal database codes but displays human-readable labels in Aurena. OData queries must use the display value (e.g., `State eq 'Planned'`), not the internal code. If the filter returns empty results, check whether you are using the correct display value. [src4]
- **Date/time handling**: IFS Cloud dates follow the instance's configured time zone. OData responses may or may not include timezone offset depending on the projection configuration. Always test date filtering with known records to confirm timezone behavior. [src4]
- **Custom field naming conventions**: Custom fields added in the Cust layer follow IFS naming conventions (`Cf$FieldName` pattern in some configurations). The OData property name matches the Marble attribute name, not the database column name. [src2]
- **Reference description expansion**: Reference fields (like CustomerNo) only return the key value by default. To get the customer name alongside the key, you must use `$expand=CustomerRef` or include the description attribute in a custom projection. [src4]

## Error Handling & Failure Points

### Common Error Codes

| Code | Meaning | Cause | Resolution |
|---|---|---|---|
| 400 Bad Request | Validation error | Invalid field value, missing required field, or malformed OData query | Parse the OData error response body for field-level details [src4] |
| 401 Unauthorized | Authentication failure | Expired OAuth token, invalid credentials, or wrong authentication method for path | Re-authenticate; for /main/ use OAuth, for /int/ use Basic Auth [src5] |
| 403 Forbidden | Insufficient permissions | Valid token but user lacks IFS permission set for the projection | Check IFS Cloud permission sets — projection-level access is separate from page-level [src5, src6] |
| 404 Not Found | Projection or entity not found | Wrong projection name, entity set name, or record key | Verify names in API Explorer; names are case-sensitive [src4] |
| 500 Internal Server Error | Server-side failure | PL/SQL error in projection logic, database constraint violation | Check IFS Cloud application server logs; may require IFS support [src4] |
| 502/503 | Service unavailable | IFS Cloud deployment in progress or server overload | Retry with exponential backoff; check IFS Cloud status page |

[src4, src5]

### Failure Points in Production

- **OAuth token expiry during batch operations**: If a batch job runs longer than the OAuth token lifetime (often 5-15 minutes), subsequent requests fail with 401 mid-batch. Fix: `Implement token refresh logic that checks token expiry before each request. Request tokens with appropriate lifetime or use refresh tokens.` [src5, src6]
- **Cust layer conflicts after IFS Cloud upgrade**: When IFS releases a new version that restructures a page or projection you have customized with `@Overtake`, the customization may conflict with new base layer changes. Fix: `Use @Override instead of @Overtake wherever possible. Run IFS Configuration Analyzer and Lobby Analyzer before accepting an upgrade.` [src2, src7]
- **Missing permissions on new custom projections**: A newly deployed custom projection is accessible to admin users but returns 403 for regular users. Fix: `Create and assign an IFS permission set that grants access to the new projection. Projection permissions are separate from page permissions.` [src5]
- **Integration projection left with Basic Auth in production**: Projections set to Integration category during development remain accessible via Basic Auth in production, creating a security risk. Fix: `Audit all Integration-category projections before production deployment. Switch to OAuth-only where possible. If Basic Auth is required, restrict network access via firewall rules.` [src5]
- **Lobby data sources returning stale data**: Lobby elements using SQL data sources may cache results, showing stale KPI data. Fix: `Configure the lobby element refresh interval. For real-time data, use Information Sources with appropriate cache settings rather than static SQL queries.` [src1]

## Anti-Patterns

### Wrong: Modifying base layer files directly

```plaintext
-- BAD -- modifying the base layer file directly
-- File: CustomerOrderHandling.client (base layer)
client CustomerOrderHandling;
component ORDER;
layer Core;

page CustomerOrderForm using CustomerOrderSet {
   -- Adding custom field directly in base layer
   field MyCustomField;  -- This will be overwritten on next IFS upgrade
}
```

### Correct: Use Cust layer with @Override annotation

```plaintext
-- GOOD -- customization in separate Cust layer file
-- File: CustomerOrderHandling-Cust.client
client CustomerOrderHandlingCust;
component ORDER;
layer Cust;

@Override
page CustomerOrderForm using CustomerOrderSet {
   field MyCustomField after ExistingField {
      label = "Custom Reference";
   }
}
```

### Wrong: Using @Override on commands (causes deployment error)

```plaintext
-- BAD -- commands are atomic and cannot use @Override
@Override
command ApproveOrderCommand {
   label = "Custom Approve";  -- This will fail during code generation
}
```

### Correct: Use @Overtake to completely replace commands

```plaintext
-- GOOD -- @Overtake replaces the entire command definition
@Overtake
command ApproveOrderCommand {
   label = "Custom Approve";
   enabled = [Status = "Planned"];
   execute {
      call ApproveOrder(OrderNo);
      refresh;
      success("Order approved successfully");
   }
}
```

### Wrong: Hardcoding projection endpoint URLs with /main/ for middleware

```python
# BAD -- middleware using OAuth may be complex to configure;
# hardcoding /main/ when Basic Auth is needed
url = "https://instance.ifs.cloud/main/ifsapplications/projection/v1/CustomerHandling.svc/CustomerSet"
response = requests.get(url, auth=("user", "pass"))  # 401 — Basic Auth not accepted on /main/
```

### Correct: Use /int/ path for Basic Auth middleware integrations

```python
# GOOD -- use Integration path for Basic Auth
url = "https://instance.ifs.cloud/int/ifsapplications/projection/v1/CustomerHandling.svc/CustomerSet"
response = requests.get(url, auth=("integration_user", "password"))  # Works with Basic Auth
```

## Common Pitfalls

- **Using @Overtake when @Override would suffice**: `@Overtake` replaces the entire original definition, meaning you lose any changes IFS makes to the base in future upgrades. If you only need to add fields or change labels, `@Override` merges your changes and preserves the base. Fix: `Only use @Overtake for commands (which require it) and for cases where the base behavior must be fundamentally changed. Use @Override for additive changes.` [src2]
- **Forgetting to add custom attributes to the projection**: Adding a custom field to the `.client-Cust` file without adding the corresponding attribute to the `.projection-Cust` file results in a deployment error — the client references an attribute that does not exist in the data model. Fix: `Always modify both .client-Cust and .projection-Cust files together. The projection defines what data is available; the client defines how it is displayed.` [src2]
- **Not running Configuration Analyzer before upgrades**: IFS Cloud upgrades can conflict with Cust layer customizations. The Configuration Analyzer identifies conflicts before they cause deployment failures. Fix: `Run Configuration Analyzer, Lobby Analyzer, and Update Analyzer before accepting any IFS Cloud version upgrade.` [src7]
- **Exposing all projections for Integration without security review**: Changing a projection to Integration category enables Basic Auth, which may bypass SSO policies. Fix: `Maintain a register of all Integration-category projections. Review each one for security implications. Prefer OAuth and the /main/ path wherever the consuming system supports it.` [src5]
- **Ignoring the .plsvc file for custom actions**: Defining a custom action in a `.projection` file without implementing the PL/SQL logic in the corresponding `.plsvc` file causes runtime errors when the action is invoked. Fix: `For every custom action or function in a projection, create the corresponding PL/SQL implementation in the .plsvc file. Use IFS Developer Studio to generate the skeleton.` [src1, src2]
- **Not testing OData filter syntax against IFS implementation**: IFS Cloud's OData implementation does not support all standard OData v4 query options. Features like `$count`, `$search`, and complex lambda expressions may not work. Fix: `Test each OData query option against your IFS Cloud instance. Use API Explorer to validate queries before building integration logic.` [src4]

## Diagnostic Commands

```bash
# Test OAuth token against IFS Cloud
curl -s "https://yourinstance.ifs.cloud/main/ifsapplications/projection/v1/" \
  -H "Authorization: Bearer $TOKEN" \
  -H "Accept: application/json"

# Get OData metadata for a specific projection
curl -s "https://yourinstance.ifs.cloud/main/ifsapplications/projection/v1/CustomerHandling.svc/\$metadata" \
  -H "Authorization: Bearer $TOKEN" \
  -H "Accept: application/xml" | head -50

# Test Basic Auth on Integration path
curl -s "https://yourinstance.ifs.cloud/int/ifsapplications/projection/v1/CustomerHandling.svc/CustomerSet?\$top=1" \
  -u "integration_user:password" \
  -H "Accept: application/json"

# Discover OpenID Connect configuration
curl -s "https://yourinstance.ifs.cloud/.well-known/openid-configuration" | python3 -m json.tool

# Verify projection entity set schema
curl -s "https://yourinstance.ifs.cloud/main/ifsapplications/projection/v1/CustomerOrderHandling.svc/\$metadata" \
  -H "Authorization: Bearer $TOKEN" | python3 -c "
import sys
content = sys.stdin.read()
# Look for EntityType definitions
for line in content.split('\n'):
    if 'EntityType' in line or 'Property' in line:
        print(line.strip())
"
```

## Version History & Compatibility

| IFS Cloud Version | Release Date | Status | Key Extensibility Changes | Migration Notes |
|---|---|---|---|---|
| 24R2 | 2024-11 | Current | Enhanced OAuth in IFS REST Task; externalized URL configuration in workflows | Audit workflow REST tasks for new OAuth configuration options [src8] |
| 24R1 | 2024-05 | Supported | External REST API calls from workflows (IFS REST Task); improved projection configuration | New capability — no breaking changes [src8] |
| 23R2 | 2023-11 | Supported | Solution Manager enhancements; improved API Explorer | N/A |
| 23R1 | 2023-05 | Supported | Custom Projection assistant in Solution Manager; entity configuration improvements | Low-code projection creation reduces need for Developer Studio |
| 22R2 | 2022-11 | Legacy | Projection-level security enhancements | Consider upgrading for latest security features |
| 22R1 | 2022-05 | EOL | Baseline for current extensibility model | Minimum version for full Aurena extensibility support |

[src1, src8]

### Deprecation Policy

IFS follows a continuous release model for IFS Cloud, with two major releases per year (R1 in spring, R2 in autumn). Each release is supported for approximately 2 years. The Aurena extensibility model is forward-compatible — customizations built on the Cust layer using `@Override` and `@Overtake` carry forward across upgrades, though `@Overtake` customizations should be reviewed against each new release for conflicts. The legacy Enterprise Explorer client continues to be supported alongside Aurena but receives no new extensibility features. [src1, src3]

## When to Use / When Not to Use

| Use When | Don't Use When | Use Instead |
|---|---|---|
| Extending IFS Aurena pages with custom fields, groups, or commands | Building entirely separate web applications that happen to read IFS data | Direct OData API integration without Aurena framework |
| Creating custom projections to expose IFS data as OData APIs | Needing hard numeric rate limits and SLA-guaranteed API throughput | Consider IFS Connect or middleware with rate management |
| Configuring lobby dashboards with KPI elements and navigation | Needing real-time streaming / CDC (change data capture) | IFS Business Events + external event processing |
| Non-intrusive customizations that must survive IFS Cloud upgrades | Modifying core IFS business logic in PL/SQL base packages | IFS Developer Studio extension layer with IFS partnership |
| Middleware integration via Basic Auth on Integration-category projections | Complex multi-step orchestration across multiple ERP systems | iPaaS (MuleSoft, Boomi, Workato) with IFS OData connector |

## Important Caveats

- IFS Cloud does not publish hard numeric API rate limits. Throughput depends on your specific deployment configuration, tenant sizing, and IFS Cloud infrastructure tier. For high-volume integration requirements, engage IFS support to understand your deployment's capacity. [src5]
- The Aurena extensibility model (Cust layer, @Override, @Overtake) is specific to IFS Cloud. IFS Applications 10 (on-premise) uses a different customization framework — do not confuse the two. [src1, src3]
- Lobby element design still requires Enterprise Explorer (EE), even though lobbies display in Aurena. This is a gap in the Aurena-first strategy that IFS may address in future releases. [src1]
- Integration-category projections with Basic Auth bypass OAuth/SSO security. This is a deliberate trade-off for middleware compatibility, but it must be accompanied by network-level security controls (IP whitelisting, VPN). [src5]
- The Marble DSL is proprietary to IFS — there is no open-source tooling or community IDE support. Development requires IFS Developer Studio, which is only available to licensed IFS customers and partners. [src1, src7]
- Custom projections and pages are deployment artifacts, not configuration data. They cannot be exported/imported through user-facing screens — they must be packaged as IFS Cloud components and deployed through the IFS Cloud lifecycle management process. [src2, src3]

## Related Units

- [IFS Cloud OData/REST API capabilities and rate limits](/business/erp-integration/ifs-cloud-rest-api/2026)
- [IFS Cloud middleware integration playbooks](/business/erp-integration/ifs-middleware-integration/2026)
- [SAP S/4HANA extensibility model for comparison](/business/erp-integration/sap-extensibility/2026)
