Skip to content

Other endpoints

Beyond the object surface, the engine exposes these controller areas. Each base route hosts the operations for one feature; follow the linked guide for behaviour and payloads.

Base route Controller Covers
/api/v1/auth AuthController Login, refresh, logout, MFA challenge/verify, password reset.
/api/v1/genie/auth AuthorizationBoardController The Access Dashboard: statistics, the access workspace (/board/principals for the rail and scope options, /board/matrix for one principal’s access, /board/apply for a batch of toggles), the access-explorer trees, and RBAC import/export. /board/matrix accepts a Scope of All/Global/Company that only ever narrows the caller’s own scope. Open to System, Admin and AccessManager; import/export is System-only.
/api/v1/genie/company CompanyController Tenant/company listing & switching.
/api/v1/impersonation ImpersonationController Start impersonating a user (System role) and stop again (any authenticated session — it runs as the impersonated user).
/api/v1/genie/timezone TimeZoneController Get/set the user’s IANA time zone.

See Identity, RBAC & permissions and Multi-tenant company scoping.

Base route Controller Covers
/api/v1/genie/navbar NavbarController The permission-filtered navigation tree (badge-free, returns fast).
/api/v1/genie/navbar/badges NavbarController Computed badge values (counts / dots) keyed by item name, fetched separately so the tree renders first.
/api/v1/genie/search SearchController Global search (SQL or Meilisearch provider).
/report ReportController Code-defined reports: GET /report lists them, GET /report/{key} generates one (?inline=true to preview rather than download). A root route, not under /api/v1/genie.
/files/{path} FileController Streams a stored file (attachment/export/temp), inline where the type allows. Also a root route.

See Navigation, Search and Reports.

Base route Controller Covers
/api/v1/notification NotificationController A user’s notifications.
/api/v1/notifications NotificationApiController Notification API surface.
/api/v1/push-subscription PushSubscriptionController Web-push subscription management.

Real-time delivery is over SignalR — see Notifications.

Base route Controller Covers
/api/v1/genie/wizard WizardController Wizard execution and form generation.
/api/v1/genie/workflow WorkflowDesignerController Workflow definitions, instances and the designer.

See Wizards and Workflows.

Two calls, mirroring the object endpoints’ structure/data split: structure is SQL-free and fetched once, data is gated and re-fetched per filter change.

Method & route Returns Gate
GET /api/v1/genie/reports/{key} The report’s filters, widgets, layout and dataset names/modes. Every [SqlBody] property is stripped, so no query text leaves the server. Authentication only
POST /api/v1/genie/reports/{key}/data Every dataset a visible widget reads, executed once each. List on the report’s RBAC resource

{key} is the report’s Name or Slug. Plural /reports — distinct from the singular /report/{key} at the API root, which belongs to the unrelated code-defined PDF feature.

// POST /api/v1/genie/reports/inventory-overview/data
{
"Arguments": { "FltWarehouse": "3", "FltRangeFrom": "2026-08-27", "FltRangeTo": "2026-09-09" }
}
// → SuccessDataResult<ReportDataResult>
{
"success": true,
"data": {
"Name": "InventoryOverview",
"RequiredFilterMissing": false,
"DataSets": {
"DsKpis": {
"Columns": [{ "Name": "StockValue", "ClrType": "Decimal" }],
"Rows": [{ "StockValue": "1284750.00" }]
}
},
"AccessibleWidgets": ["TlStockValue", "ChCategoryValue", "VwLowStock"]
}
}

Three things to note about the response:

  • RequiredFilterMissing: true means no dataset ran at all. A blank required filter gates the whole page; DataSets is empty and the client shows a prompt.
  • AccessibleWidgets is authoritative. A widget withheld by RolesAllowed is absent, and so is any dataset only it read — the client closes the layout over it.
  • Every cell is a string or null, numbers included, matching the grid. Client code must parse and guard NaN.

An embedded <View> widget is not served by these endpoints: it fetches through the ordinary object endpoints under its own resource, so embedding never launders a permission.

See Report pages and Runtime & sources.

Ten more calls, behind ReportDesignerController. Separate from the two above on purpose: those run a report for a viewer and are gated on the report’s own resource, these edit the document and are gated on the definitions grid’s resource — merging them would put a viewer’s read path and an author’s write path behind one permission.

Method & route Returns Gate
GET /api/v1/genie/report-designer/definitions/{key} The definition’s identity plus its source XML. DefinitionXml is null for a row stored before the XML was retained. View on ReportDefinitions
POST /api/v1/genie/report-designer/definitions/save Upserts by the document’s own Name, so one call both creates and updates. A parse error is a 4xx carrying the parser’s message. Update on ReportDefinitions
GET …/definitions/{key}/versions Every version, newest first, with the current one flagged. View on ReportDefinitions
GET …/definitions/{key}/versions/{versionHash} The document as that version saved it. View on ReportDefinitions

The draft lifecycle. {key} addresses the stored report by Name or Slug — never the draft document’s own name, which the author may have changed:

Method & route Returns Gate
GET …/definitions/{key}/draft The report’s draft, or null. Includes IsStale, true when the published document moved since the draft forked. View on ReportDefinitions
POST …/definitions/{key}/draft Creates or replaces the draft. Not versioned, and not parsed — a draft is allowed to hold text the parser would reject. Update on ReportDefinitions
DELETE …/definitions/{key}/draft Discards the draft. false when there was none — idempotent, so a stale grid’s second click is not a 404. Update on ReportDefinitions
POST …/definitions/{key}/publish Promotes the draft: appends a version, repoints the report, clears the draft. Unchanged: true when the draft matched what was live (nothing appended, draft still cleared). A 4xx when the draft will not parse, or when publishing would rename the report onto a name another one holds. Update on ReportDefinitions
GET …/definitions/{key}/draft/structure The draft’s structure, SQL-free. Update on ReportDefinitions
POST …/definitions/{key}/draft/data The draft’s datasets. Update on ReportDefinitions

The last two are Update, not View, and they match each other deliberately. Running an unpublished document is more than reading one; and giving structure the weaker gate would let a client render a layout it can never fill. They exist as their own endpoints rather than a ?draft=1 flag on GET /reports/{key} because that call is ungated beyond authentication — right for a published layout, a disclosure for an author’s work in progress.

Row-level security in a draft preview resolves against the stored report’s resource name, so renaming a draft is not a way out of a row filter.

// POST /api/v1/genie/report-designer/definitions/save
{
"DefinitionXml": "<Report Name=\"InventoryOverview\" Slug=\"inventory-overview\"> … </Report>",
"Notes": "Added the supplier-mix chart"
}
// → SuccessDataResult<ReportSaveResult>
{
"success": true,
"data": {
"Name": "InventoryOverview",
"Slug": "inventory-overview",
"Created": false,
// True when the incoming text matched what was stored: nothing written, no version appended.
"Unchanged": false,
"VersionHash": "4f9c2a"
}
}

Restoring a version is a save with the text …/versions/{versionHash} returns — it appends a new version rather than rewriting history, which is why there is no restore endpoint. See The report designer.

Base route Controller Covers
/api/v1/genie/hosted-services HostedServicesController Start/stop/inspect background hosted services.
/api/v1/hangfire HangfireController Hangfire job info.
/api/v1/genie/execute-script ExecuteScriptController Execute a registered server script.
/api/v1/genie/object/list, /api/v1/genie/scripts ModelCatalogController Read the model catalog (see below).
/api/v1/genie/handlers GenieHandlersController Pluggable export/import handlers.
(files) FileController File download/serving.

The read counterpart of execute-script — deploy writes the catalog, these read it back. All three are gated to the System role, because script bodies contain the authored SQL that the metadata endpoints deliberately never expose:

Endpoint Returns
GET /api/v1/genie/object/list Every deployed object (ViewStore): Name, Slug, Label, ViewType, VersionHash.
GET /api/v1/genie/scripts?type= Executed scripts, latest per name, optionally filtered by type (ObjectView/Entity/Navbar/StoredProcedure/Rbac).
GET /api/v1/genie/scripts/{name} One script’s latest execution including its verbatim authored body (matched by Name or FileName).

This is what lets an external client (GenieClient CLI/MCP) enumerate a deployment with no local checkout, export the deployed XML, and diff a local model file against the source that is actually live (VersionHash is the MD5 of the deployed body, so an identical hash ends the question).

See Background jobs & hosted services.

The assistant chat is delivered over a SignalR hub rather than a REST controller, with a supporting natural-language-query endpoint. See AI Assistant.