Reports Reference

Schema, REST endpoints, widget catalogue, grid constraints, and permission reference for the octoja Reports area.

Written By Erdinc Akay

Last updated 26 days ago

The Reports area builds custom PDF reports from a library of widgets. This page documents the behaviours, permissions, layout grid, and widget catalogue that the schema alone cannot express.

For the complete, always-current list of endpoints, parameters, and response fields for the version you are running, use the interactive OpenAPI (Swagger) interface at https://<your-octoja-instance>/openapi/index.html.

For an end-to-end walkthrough of creating a template and generating a PDF, see Create a report template.

REST endpoints

All Reports endpoints live under /api/reports/. The Notes column carries the required permission (octoja uses custom permission policies that are not all expressed in Swagger) plus the non-obvious behaviour.

OperationEndpointNotes
GET/api/reports/templatesList all templates (built-in + custom). Permission: none β€” any logged-in user.
GET/api/reports/templates/{id}Retrieve one template with its full rows + widgets payload. Permission: none β€” any logged-in user.
POST/api/reports/templatesCreate a template. If cloneFromTemplateId is set, the new template starts as a deep copy of that template's rows + widgets. Permission: reports.manage.
POST/api/reports/templates/{id}Update a template (UpdateValue envelope β€” see below). Permission: reports.manage.
DELETE/api/reports/templates/{id}Delete a custom template. Built-in templates are protected server-side and return an error on delete. Permission: reports.manage.
GET/api/reports/widgets/availableList the live widget definitions for the editor palette β€” the authoritative catalogue for the current build. Permission: reports.manage.
POST/api/reports/preview/draftRender the same HTML used for the PDF from an in-memory { customerId, siteId, rows } body. Used by the editor preview iframe. Permission: none β€” any logged-in user.
POST/api/reports/generateGenerate a PDF. Honours the Accept-Language header for the PDF locale; returns an application/pdf response with content-disposition carrying the filename. Permission: none β€” any logged-in user.
GET/api/reports/print-bundle/{file}Serves the static print bundle (CSS, fonts) referenced by the rendered HTML. Internal β€” called by Gotenberg during PDF rendering.
GET/api/reports/schedulesList all report schedules. Permission: reports.view.
GET/api/reports/schedules/{id}Retrieve one schedule with its templates, receivers, and recent-run history. Permission: reports.view.
POST/api/reports/schedulesCreate a schedule (see Scheduling below). Permission: reports.manage.
POST/api/reports/schedules/{id}Update a schedule. Permission: reports.manage.
DELETE/api/reports/schedules/{id}Delete a schedule. Permission: reports.manage.
POST/api/reports/schedules/{id}/run-nowRun a schedule immediately β€” generates and emails the PDFs without waiting for the next cron tick. Permission: reports.manage.

Behaviours worth knowing

  • Clone on create: cloneFromTemplateId must be a GUID-formatted string when present; the new template is a deep copy of the source's rows + widgets.
  • UpdateValue envelope: the update body wraps each field, e.g. { name?: { hasValue: true, value }, rows?: { hasValue: true, value }, orientation?: { hasValue: true, value } }. The update is partial β€” fields omitted from the body (or sent without hasValue: true) are left untouched on the stored template, not cleared.
  • Generate range: the optional rangeStart / rangeEnd (ISO dates) restrict time-windowed widgets to a reporting period β€” pass both or neither; omit them for an all-time report.

Schema and fields

The full field list and types for ReportTemplate, ReportRow, and ReportWidget are in Swagger. The fields below carry behaviour the schema cannot convey.

  • name β€” for built-in templates this is an i18n key (e.g. pages.reports.builtIns.executiveSnapshot.name), localized on display; for custom templates it is the literal user-entered string.
  • isBuiltIn β€” response-only / derived. Server-computed from a built-in id allowlist rather than persisted on the entity; true for templates that ship with octoja, false for tenant-created custom templates.
  • slug β€” PDF download filename base. Built-ins only β€” executive-snapshot produces executive-snapshot-2026-04-20.pdf; custom templates fall back to a slugified name (default null).
  • iconName β€” Lucide icon component name on the template card. Built-ins only (default null).
  • orientation β€” Portrait (default) or Landscape. Landscape fits wide tables such as the hardware inventory; an invalid value returns 400 Bad Request.
  • columnSpan (widget) β€” number of grid columns occupied (default 1). Bounded per-widget; each widget type declares its own minColumnSpan, maxColumnSpan, and defaultColumnSpan, which the editor enforces.
  • rowSpan (widget) β€” height in editor rows; 0 (default) means "use the widget's default row span".
  • config (widget) β€” widget-specific settings whose shape depends on the widget type; refer to the editor's properties panel for the available options.
  • backgroundColor (widget) β€” one of a fixed set of tints (Indigo, Emerald, Amber, Sky, Rose, Slate); the Callout widget uses the same set.
  • autoStatusColor (widget) β€” when true, data-driven widgets (KPI cards, gauges) tint themselves by the value's severity (green OK, amber Warning, red Critical). No effect on widgets that declare no auto-status thresholds.

A ReportRow has no configurable properties of its own β€” it groups widgets horizontally and triggers a natural page break when the grid runs out of room.

The four-column grid

The report canvas is a fixed four-column grid. Each widget's columnSpan declares how many of the four columns it occupies. A row can hold any combination of widgets whose columnSpan values sum to four or less. When you add a fifth widget to a row that already sums to four, octoja places it in a new row.

Typical spans: 1 = quarter-width (KPI cards, small gauges); 2 = half-width (info cards, charts); 3 = three-quarters (a wide table beside a narrow card); 4 = full-width (hero charts, tables that need every column).

Widget catalogue

Widgets are grouped into six categories β€” KPI cards, Charts, Tables, Info cards, Layout, and Checks. The notes below capture each widget's scope-awareness and any non-obvious behaviour; GET /api/reports/widgets/available returns the authoritative live catalogue for the current build. Unless noted otherwise, every data widget is scope-aware (it honours the report's customer / site filters).

KPI cards (Kpi)

Single-value indicators with a coloured header and an optional auto-status tint. The catalogue is large and grows with the product β€” examples include Total Devices, Online Devices, Open Cases (count of non-closed cases β€” any status other than Closed), Health Score, Low Disk Devices, Patch Compliance, Certs Expiring ≀30d, Check Success Rate, plus activity, backup, monitoring, Lywand, software-inventory, and incident KPIs. All KPI cards are scope-aware.

Charts (Chart)

  • Device Age (bar chart) β€” histogram of devices by age band (e.g. < 1y, 1–3y, 3–5y, > 5y).
  • OS Distribution (bar chart) β€” devices grouped by operating system family.
  • Device Kinds (donut) β€” devices grouped by kind (workstation, server, etc.).
  • Disk Usage Buckets (donut) β€” devices grouped by overall disk-usage bucket.
  • Cases by Priority (donut) β€” non-closed cases grouped by priority. Closed cases are excluded, matching the Open Cases KPI.
  • Activity by Source (donut) β€” activity events grouped by source.
  • Check Status Distribution (donut) β€” a selected check's result distribution (Ok / Warning / Critical / Unknown).
  • Check Status History (chart) β€” time-series of a selected check's result history across the scope.

Tables (Table)

  • All Devices β€” devices with name, OS, last-seen, and health.
  • Recent Cases β€” recent cases with title, status, priority, customer, and date.
  • Certificate Expiry Table β€” certificates due to expire, grouped by days remaining.
  • Disk Space Table β€” devices ordered by least free disk space.
  • Top Manufacturers β€” devices grouped by hardware manufacturer.
  • Check Results Table β€” per-device results for a selected check (status, value, last evaluated).
  • Incident Timeline β€” chronological list of incidents within the scope.
  • Backup Status β€” backup job runs with target, status, and last success.
  • Local Users β€” local accounts present on devices in the scope.
  • Vulnerabilities β€” vulnerability findings surfaced by the Lywand integration.
  • Monitoring Summary β€” monitoring check state across devices.
  • Top Installed Software β€” most-installed software titles across the scope's devices.
  • Hardware Inventory β€” one row per device with a configurable set of hardware fields, grouped into System, Identity, CPU, Memory, Storage, and Network.
  • Patch History β€” installed updates per device, with KB number and install date.
  • Pending Patches β€” updates still outstanding per device.

Info cards (Info)

  • Device Summary β€” server-resolved roll-up of devices in scope (totals + breakdown).
  • Customer Breakdown β€” server-resolved customer roll-up (names + counts), filtered by the report's customer and site scope.
  • Gauge (Static) β€” single gauge with a configurable value range and severity thresholds. Author-provided value β€” does not query live data and is not scope-aware.

Checks (Checks)

  • Check Detail β€” detail card for a single check (current state, last result, configuration summary).
  • Check History (per device) β€” per-device result history for a single check, one entry per device with its recent trend. Can be narrowed to specific devices or statuses.
  • Check Status Timeline β€” timeline of a single check's state transitions across the scope.

Layout (Layout)

Structural widgets β€” no live data, and not scope-aware.

  • Heading β€” section heading text.
  • Paragraph β€” body paragraph text.
  • Callout β€” coloured callout box with one of the six background colours.
  • Bullet List β€” bullet list with marker style Dot, Check, or Dash.
  • Divider β€” horizontal rule.
  • Spacer β€” vertical whitespace.
  • Page Break β€” forces a page break at this point in the PDF.
  • Traffic Lights β€” author-curated grid of status cells (Ok / Warning / Critical / Unknown).

Scope semantics

When a report is generated, the request payload carries customerId? and siteId? β€” both optional, and a siteId is only meaningful when paired with a customerId. The renderer narrows every scope-aware widget's data query to that customer (and optional site).

Widgets that are not scope-aware (the Gauge and all Layout widgets) ignore the scope β€” their content is author-provided and renders the same regardless of customerId / siteId.

Scope is not stored on the template. It is a generate-time parameter β€” the same template can produce a tenant-wide report, a per-customer report, or a per-site report depending on what is passed to the generate call.

Built-in vs custom templates

Both types share the same schema and editor experience. The differences are behavioural:

  • Created by β€” built-in ships with octoja; custom is created by you.
  • name β€” built-in is an i18n key (localized on display); custom is the literal user string.
  • slug / iconName β€” set on built-ins (slug drives the PDF filename, iconName the card icon); null on custom (filename slugified from name, generic template icon).
  • Edit β€” built-ins are read-only; clone first to customize. Custom templates are editable.
  • Delete β€” built-ins are protected server-side; custom templates are deletable.
  • Duplicate β€” allowed for both, and always produces a new custom template.

Permission

reports.manage β€” creating, editing, deleting, and renaming custom templates. Generating reports and viewing the template list do not require it.

Granted via groups in Administration β†’ Groups.

PDF filename

The generated PDF's filename is set by the content-disposition header on the response:

  • Built-in template: <slug>-<yyyy-mm-dd>.pdf (e.g. executive-snapshot-2026-04-20.pdf).
  • Custom template: <slugified-name>-<yyyy-mm-dd>.pdf (e.g. quarterly-customer-review-2026-04-20.pdf).

The date is the date of generation. The report's data window is a separate setting: the optional rangeStart / rangeEnd reporting period on the generate call (the Period selector in the UI, with All time, Current month, Last month, and Custom presets). Time-windowed widgets honour it; point-in-time widgets such as the inventory tables always reflect the current state.

PDF language

The PDF locale follows the Accept-Language request header. octoja always sets this to the user's current UI language at the moment Generate is clicked. To produce a German PDF from an English UI, switch the language picker first and then click Generate β€” the next click produces a German PDF.

Scheduling

Reports can be delivered automatically on a recurring basis. A schedule bundles one or more report templates with a cron expression and a set of receivers; when the schedule fires, octoja generates each template as a PDF and emails it to the receivers. The reports page has a Scheduling entry that opens this management area.

  • cron β€” a standard 5-field cron expression, evaluated in UTC. It is validated on save; an invalid expression returns 400 Bad Request.
  • receivers β€” one or more entries, each pairing a customerId (required), an optional siteId (only meaningful with a customer), and a list of recipient emails. Each receiver defines the report scope for the PDFs it gets β€” the same customer/site narrowing described under Scope semantics.
  • enabled β€” a disabled schedule is retained but never fires; the next run time is only computed while it is enabled.
  • subject β€” optional custom subject line for the delivery email; leave it empty for the default.

Creating, updating, and deleting schedules β€” as well as running one immediately β€” require reports.manage. Listing and viewing schedules require only reports.view.

Related articles