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:
| Component | Description |
|---|
| Name | Display name in the sidebar and settings |
| Slug | Unique technical identifier (e.g. my-dashboard) |
| Description | Optional description of the app’s purpose |
| Provider | Optional: Who created the app |
| Executor | The 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>")
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¶m2=value2
Managing Apps
App management is available under Settings → Advanced Settings → Apps.
Creating a New App
- Navigate to Settings → Apps
- Click Create App
- Enter name, slug, and optionally a description
- Write the executor code
- Use the Preview to verify the output
- 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
| Permission | Description | Default Roles |
|---|
readApps | View and run apps | Admin, Agent |
appCreator | Create, edit, and preview apps | Admin |
manageApps | Import and delete apps | Admin |
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>
""")
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
| Method | Endpoint | Description |
|---|
GET | /api/mind/app | List all apps |
POST | /api/mind/app | Create 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}/revisions | List all revisions |
POST | /api/mind/app/{appId}/rollback/{revision} | Roll back to a revision |
POST | /api/mind/app/{appId}/preview | Run preview |
POST | /api/mind/app/import | Import app |
GET/POST | /api/mind/app/{appId}/run | Run app (HTML response) |