Skip to main content
Preview Feature — Apps is currently in preview. Functionality and API may still change. We welcome your feedback!
Apps allow you to create and run custom HTML applications directly within Enneo. Use apps for custom dashboards, reports, forms, or tools — all within the familiar Enneo interface.

Overview

Apps are custom applications that return HTML and are displayed directly as a dedicated page within Enneo. Each app runs in a sandbox and has access to the Enneo API. Common use cases:
  • Custom dashboards — Visualize real-time data from your ERP or CRM
  • Reports and analytics — Tailored reports with custom logic
  • Internal tools — Forms, calculators, or workflow helpers
  • Data queries — Display contract data, customer status, or statistics

Structure of an App

Each app consists of:
ComponentDescription
NameDisplay name in the sidebar and settings
SlugUnique technical identifier (e.g. my-dashboard)
DescriptionOptional description of the app’s purpose
ProviderOptional: Who created the app
ExecutorThe code that runs on each invocation (Python, Node.js, or PHP)

Executor Code

The executor code runs every time the app is called. 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

Each invocation automatically receives metadata as parameters:
{
  "_metadata": {
    "userId": 1,
    "clientId": "1",
    "appId": "a1b2c3d4-..."
  }
}
Additional GET or POST parameters are automatically passed through and available in the code.

Using Apps

Once at least one app exists and the user has the readApps permission, the Apps menu item appears in the sidebar. All available apps are displayed as tabs.

Running an App

Each app runs inside an iFrame within Enneo. The app URL is:
/api/mind/app/{appId}/run
GET parameters can be appended directly:
/api/mind/app/{appId}/run?param1=value1&param2=value2

Managing Apps

App management is available under Settings → Advanced Settings → Apps.

Creating a New App

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

Editing an App

Each change automatically creates a new revision. This allows you to return to a previous version at any time.

Revisions and Rollback

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

Importing an App

Apps can be imported via JSON. This enables transfer between environments.

Permissions

PermissionDescriptionDefault 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>
""")

Simple Ticket Search Form

import importlib.util, os, json, sys

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()
search_query = input_data.get('q', '')

html = """
<!DOCTYPE html>
<html>
<head>
    <style>
        body { font-family: Arial, sans-serif; padding: 20px; }
        input { padding: 8px; width: 300px; border: 1px solid #ccc; border-radius: 4px; }
        button { padding: 8px 16px; background: #9575ef; color: white; border: none;
                 border-radius: 4px; cursor: pointer; }
        table { width: 100%; border-collapse: collapse; margin-top: 16px; }
        th, td { padding: 8px; text-align: left; border-bottom: 1px solid #eee; }
        th { background: #f5f5f5; }
    </style>
</head>
<body>
    <h1>Ticket Search</h1>
    <form method="GET">
        <input name="q" placeholder="Search..." value="{QUERY}">
        <button type="submit">Search</button>
    </form>
"""

html = html.replace("{QUERY}", search_query)

if search_query:
    try:
        results = sdk.ApiEnneo.get('/api/mind/ticket/search', {
            'q': search_query,
            'limit': 10
        }, 'serviceWorker')
        tickets = results.get('tickets', [])

        html += "<table><tr><th>ID</th><th>Subject</th><th>Status</th></tr>"
        for t in tickets:
            html += f"<tr><td>{t['id']}</td><td>{t.get('subject','')}</td>"
            html += f"<td>{t.get('status','')}</td></tr>"
        html += "</table>"

        if not tickets:
            html += "<p>No results found.</p>"
    except Exception as e:
        html += f"<p style='color:red'>Error: {e}</p>"

html += "</body></html>"
print(html)

Static Information 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 hours:</strong> Mon-Fri, 8:00 AM - 6:00 PM
    </div>
    <br>
    <div class="warning">
        <strong>Notice:</strong> Maintenance work planned for the weekend.
    </div>
</body>
</html>
""")
Apps have access to the same Enneo SDK used by rule-based AI agents. This lets you query contracts, read tickets, retrieve settings, and call external APIs. For more information, see the SDK documentation.

API Reference

MethodEndpointDescription
GET/api/mind/appList all apps
POST/api/mind/appCreate a new app
GET/api/mind/app/{appId}Get app details
PATCH/api/mind/app/{appId}Update app (creates new revision)
DELETE/api/mind/app/{appId}Delete app
GET/api/mind/app/{appId}/revisionsList all revisions
POST/api/mind/app/{appId}/rollback/{revision}Roll back to a revision
POST/api/mind/app/{appId}/previewRun preview
POST/api/mind/app/importImport app
GET/POST/api/mind/app/{appId}/runRun app (HTML response)