Skip to main content
Preview Feature — Apps is currently in the preview phase. Functionality and API can still be changed. We appreciate feedback!
Apps allow you to create and run your own HTML applications directly in Enneo. Use Apps for individual dashboards, reports, forms or tools — all within the familiar Enneo interface.

Overview

Apps are custom applications that return HTML and are displayed directly in Enneo as their own page. Each app runs in a sandbox and has access to the Enneo API. Typical use cases:
  • Individual Dashboards — visualize real-time data from the ERP or CRM
  • Reports and evaluations — tailor-made reports with own logic
  • Internal tools — forms, calculators or workflow helpers
  • Data queries — display contract data, customer status or statistics

App Structure

Each App consists of:
ComponentDescription
NameDisplay name in the sidebar and in the settings
SlugUnique technical identifier (e.g., my-dashboard). Used in the URL
DescriptionOptional description of the purpose of the App
ProviderOptional: Who has created the App
ExecutorThe code that is executed when called (Python, Node.js or PHP)

Executor

The executor uses Enneo’s standard executor format (same structure as for settings and AI agents). It currently supports the Source code type with the languages Python 3.11, Node.js 20 and PHP 8.2. The output to stdout is returned as HTML to the browser.
# Simple App: Welcome page
print("<h1>Welcome</h1>")
print("<p>This is my first Enneo app.</p>")

Input Parameters

With each call, the code automatically receives metadata as a parameter via STDIN:
{
  "_metadata": {
    "userId": 1,
    "clientId": "1",
    "appId": "a1b2c3d4-...",
    "appRevision": 3,
    "userAuthToken": "Bearer ..."
  }
}
Additional GET or POST parameters are automatically passed on and are available in the code.

Environment Variables

The following environment variables are available in the app code:
VariableDescription
ENNEO_API_URLBase URL of the Enneo API
ENNEO_SESSION_TOKENSession token for API calls
ENNEO_USER_AUTH_HEADERAuth Header of the calling user
ENNEO_APP_IDUUID of the App
ENNEO_APP_SLUGSlug of the App
ENNEO_APP_VERSIONVersion of the App (e.g., 1.0.0)
SDKPath to the SDK file

Using Apps

As soon as at least one app exists and the user has the readApps permission, the menu item Apps appears in the sidebar. All available apps are displayed as tabs here. The app-url in the browser uses the Slug of the app:
/apps/my-dashboard

Call App

Each app runs in an iFrame inside of Enneo. The API URL accepts both UUID and Slug:
/api/mind/app/{slug}/run
/api/mind/app/{appId}/run
GET parameters can be directly appended:
/api/mind/app/my-dashboard/run?param1=value1&param2=value2

App Storage

Apps can store and read persistent data. The App Storage is a key-value store, which is isolated per app. The values are stored as JSON.

SDK Access

# Save value
sdk.AppStorage.save("counter", 42)
sdk.AppStorage.save("config", {"theme": "dark", "lang": "de"})

# Read value
counter = sdk.AppStorage.get("counter")  # → 42
config = sdk.AppStorage.get("config")    # → {"theme": "dark", "lang": "de"}

# Read value with metadata
meta = sdk.AppStorage.get_meta("counter")
# → {"key": "counter", "value": 42, "createdAt": "...", "modifiedAt": "...", "lastAccessAt": "..."}

# List all keys
keys = sdk.AppStorage.list_keys()
# → [{"key": "counter", "createdAt": "...", ...}, ...]

# Delete value
sdk.AppStorage.delete("counter")

App Info

The AppInfo class can be used to retrieve app metadata:
app_id = sdk.AppInfo.get_id()        # UUID of the App
app_slug = sdk.AppInfo.get_slug()    # Slug of the App
app_version = sdk.AppInfo.get_version()  # Version (e.g., "1.0.0")

Supported Value Types

TypeExample
String"hello world"
Number42, 3.14
Booleantrue, false
Nullnull
Object{"key": "value"}
Array[1, "two", 3.0]

Manage Apps

Management is under Settings → Advanced Settings → Apps.

Create New App

  1. Navigate to Settings → Apps
  2. Click on Create App
  3. Enter name, slug and optional description
  4. Write the executor code
  5. Use the Preview to check the output
  6. Click on Save

Edit App

Each change automatically creates a new Revision. This way, you can always revert to a previous version. Unsaved changes are indicated by a Draft tag in the sidebar. A warning will appear when navigating with unsaved changes.

Export and Import

Apps can be exported and imported as JSON. The export button is located in the Specifications tab. This allows for transfer between environments.

Revisions and Rollback

Apps support versioning:
  • Each save creates a new revision
  • Through the revisions overview, you can revert to any previous version
  • The active revision is displayed to the users

Permissions

PermissionDescriptionStandard Roles
readAppsView and run AppsAdmin, Agent
appCreatorCreate, edit and preview AppsAdmin
manageAppsImport and delete AppsAdmin

Examples

Dashboard with Contract data

import importlib.util, os, json, sys

# Load SDK
file_path = os.getenv('SDK', 'sdk.py')
spec = importlib.util.spec_from_file_location('sdk', file_path)
sdk = importlib.util.module_from_spec(spec)
spec.loader.exec_module(sdk)

# Load input data
input_data = sdk.load_input_data()
metadata = input_data.get('_metadata', {})

# Load contract data (example)
contract_id = input_data.get('contractId', '715559')
try:
    contract = sdk.ApiEnneo.get_contract(contract_id)
    name = f"{contract.get('firstname', '')} {contract.get('lastname', '')}"
    status = contract.get('status', 'Unknown')
except Exception:
    name = "Not found"
    status = "-"

# Output HTML
print(f"""<!DOCTYPE html>
<html>
<head>
    <style>
        body {{ font-family: Arial, sans-serif; padding: 20px; }}
        .card {{ background: #f5f5f5; padding: 16px; border-radius: 8px; margin: 8px 0; }}
        h1 {{ color: #333; }}
    </style>
</head>
<body>
    <h1>Contract Overview</h1>
    <div class="card">
        <strong>Name:</strong> {name}<br>
        <strong>Status:</strong> {status}<br>
        <strong>Contract Number:</strong> {contract_id}
    </div>
</body>
</html>
""")

App with Persistent Counter

import importlib.util, os, json, sys, html

file_path = os.getenv('SDK', 'sdk.py')
spec = importlib.util.spec_from_file_location('sdk', file_path)
sdk = importlib.util.module_from_spec(spec)
spec.loader.exec_module(sdk)

input_data = sdk.load_input_data()

# Load the counter from the App Storage 
try:
    counter = sdk.AppStorage.get("page_views")
except Exception:
    counter = 0

# Increase and save the counter 
counter += 1
sdk.AppStorage.save("page_views", counter)

print(f"""
<!DOCTYPE html>
<html>
<body style="font-family: Arial, sans-serif; padding: 20px;">
    <h1>Visitor Counter</h1>
    <p>This page has been visited <strong>{counter}</strong> times.</p>
    <p><em>The value is stored in the App Storage and remains persistent across page loads.</em></p>
</body>
</html>
""")

Static Info Page

print("""
<!DOCTYPE html>
<html>
<head>
    <style>
        body { font-family: Arial, sans-serif; padding: 20px; max-width: 800px; margin: 0 auto; }
        .info { background: #e8f5e9; padding: 16px; border-radius: 8px;
                border-left: 4px solid #4caf50; }
        .warning { background: #fff3e0; padding: 16px; border-radius: 8px;
                   border-left: 4px solid #ff9800; }
    </style>
</head>
<body>
    <h1>Important Information</h1>
    <div class="info">
        <strong>Service times:</strong> Mon-Fri, 8:00 AM - 6:00 PM
    </div>
    <br>
    <div class="warning">
        <strong>Note:</strong> Maintenance work planned for the weekend.
    </div>
</body>
</html>
""")
Apps have access to the same Enneo SDK that is also used for rule-based AI agents. This allows contracts to be queried, tickets to be read, settings to be retrieved, and external APIs to be called. More information can be found in the SDK Documentation.

API Reference

App Management

MethodEndpointDescription
GET/api/mind/appList all apps
POST/api/mind/appCreate new app
GET/api/mind/app/{appId}Retrieve app details (UUID or Slug)
PATCH/api/mind/app/{appId}Update app (new revision)
DELETE/api/mind/app/{appId}Delete app
GET/api/mind/app/{appId}/revisionsShow all revisions
POST/api/mind/app/{appId}/rollback/{revision}Rollback to revision
POST/api/mind/app/{appId}/previewExecute preview
POST/api/mind/app/importImport app
GET/POST/api/mind/app/{appId}/runExecute app (HTML-Response)

App Storage

MethodEndpointDescription
GET/api/mind/app/{appId}/dataList all keys
GET/api/mind/app/{appId}/data/{key}Read value
GET/api/mind/app/{appId}/data/{key}/metaRead value with metadata
PUT/api/mind/app/{appId}/data/{key}Save/update value
DELETE/api/mind/app/{appId}/data/{key}Delete key
All endpoints accept both the app UUID and the slug as {appId}.

Data Format (executorUser)

The executor object in data.executorUser follows the standard executor format:
{
  "id": 1,
  "code": "print('<h1>Hello</h1>')",
  "type": "sourceCode",
  "language": "python311",
  "packages": null,
  "parameters": [],
  "parameterDefinitions": []
}