User guide

Executive Dashboards and Reporting

Looking for what it does rather than how to use it? Read the Dashboards and reporting overview .

Last verified against the codebase: 2026-07-27. See How this document is verified.


What it is

Solidlio has two reporting surfaces. Executive dashboards are live aggregates you read on screen — tickets, SLA attainment, assets, escalations, receivables and revenue, refreshed on every page load. Reports are artifacts: you queue one, a background worker aggregates and renders it, and you download a PDF, CSV or Excel file that does not change afterwards.

The split is deliberate. A dashboard answers “how are we doing right now”. A report is a document you attach to a QBR pack, hand to a client, or file for an auditor — and it must still say the same thing in six months.


Concepts

ConceptWhat it is
Executive statsA live aggregate served by one request. Three variants exist: MSP (cross-client), organization (one tenant), platform (whole install).
ReportA row in the report library (rpt_ prefix) plus, once generated, a stored file. Carries its type, format, date range, client selection and the person who ran it.
Report typeWhich aggregation runs. Ten values, mapping to six distinct aggregators plus a composable CUSTOM.
Report formatPDF, CSV or XLSX. Chosen at generate time; the artifact is rendered once in that format.
Report statusPENDING then GENERATING then COMPLETED or FAILED. The library polls while anything is in flight.
ReachEvery organization your staff work across — your own, plus every client account you primary-manage, plus every account you hold an active co-management link to.
TargetYour clients only, i.e. reach minus your own account. Client counts and client revenue use this.
Reporting periodtoday, 7d, 30d or 90d. Applies to the dashboards, not to report artifacts (those carry an explicit date range).

Reach is not target

This distinction runs through the whole MSP dashboard and is the single easiest thing to get wrong.

  • Open tickets, SLA attainment, assets, escalations are counted over reach. Your own service desk is part of your workload, and a client you co-manage under a collaborator link is too.
  • Active clients, at-risk clients, client MRR, top clients by MRR are counted over target. You are not a client of yourself, and counting your own organization would inflate the client count and put you at the top of your own revenue table.

So the client count and the ticket count are populations of different sizes on purpose. They are not meant to reconcile.


Roles and permissions

The hierarchy is platform administrator > MSP administrator > MSP technician > organization administrator > power user > CUSTOMER`.

MSP technician outranks organization administrator in that order. Reporting therefore gates on explicit role sets, never on a rank floor — a floor of MSP technician rejects every organization administrator, which is exactly the defect that used to lock org tenants out of their own exports.

Report library

platform administratorMSP administratorMSP technicianorganization administratorpower userCUSTOMER
List, read, delete reports
Generate operational reports
Generate/download Revenue, Revenue Summary, Profitability

The financial set is narrower and different, not merely stricter: a technician is admitted to the library and refused margin; an org administrator is admitted to both, because they own their own organization’s invoices.

The financial check runs on generate and on download. Reports are account-wide, so a report an administrator ran is listed to every technician on the account — gating only the queue step would let a technician download the artifact somebody else asked for.

Executive dashboards

platform administratorMSP administratorMSP technicianorganization administratorpower userCUSTOMER
MSP cross-client dashboard (operational)
MSP revenue block (MRR, growth, top clients)
Organization dashboard (operational)
Organization receivables block
Platform dashboard

A withheld block comes back null with a restricted flag, never zeroed. The UI renders a dash and a reason. This matters: “$0 outstanding” is a statement about the business, ”—” is a statement about the reader, and the two must never be confused.

The Executive and Reports sidebar entries are both gated on the canViewReports capability — true for every MSP role, and organization administrator or power user in the organization portal. Inside /org/reports, the Billing & Finance and Exports tabs are additionally hidden below organization administrator, matching the backend gates.


Walkthrough — the MSP executive dashboard

Path: MSP portal → Executive (/msp/executive)

  1. Choose a window. The selector in the header offers Today, Last 7 Days, Last 30 Days and Last 90 Days. It shifts the SLA, resolved-escalation and recent-escalation windows. Open counts are point-in-time and do not move.
  2. Read the four tiles. Client MRR (with month-over-month growth), Active Clients, Open Tickets, Assets Under Management.
  3. SLA Compliance shows response and resolution attainment as rings, plus the count of currently breached open tickets and the sample size the rates were computed over. With no SLA-tracked tickets resolved in the window, it says “No data” rather than showing a green 100%.
  4. Revenue Overview shows client MRR, the month-over-month change, and your top five clients by MRR.
  5. Escalation Trends lists active, pending and resolved escalations, a priority breakdown, and the five most recent escalation events with their ticket and organization.
  6. Client Health splits your clients into active, at-risk (suspended or inactive) and inactive, with an active-rate bar.
  7. Workload Metrics and Asset Health close the page: open, urgent, SLA-breached, unassigned, at-risk clients, assets with alerts, and warranty expiries inside 30 days.

If the plan does not include roll-up reporting, the page renders the upgrade offer the API returns — the required tier, its monthly price, and either a purchase link or “contact your account administrator”, depending on whether you can self-serve. It does not render an error.

If your role does not include financials, the revenue tile and card say “Requires an MSP administrator” and show a dash. You still get the whole operational dashboard.


Walkthrough — the organization executive dashboard

Path: Organization portal → Executive (/org/executive)

  1. Choose a window — same four options.
  2. Four tiles: Open Tickets, SLA Rate, Assets, Outstanding.
  3. SLA Compliance — response and resolution attainment over tickets resolved in the window that carry an SLA policy.
  4. Service Overview — open, in progress, urgent and SLA-breached counts, plus average resolution time. The average names the number of resolved tickets it was computed over; with nothing resolved it shows a dash, not “0 minutes”.
  5. Asset Health — total, active, with alerts, warranty expiring in 30 days.
  6. Financial Overview — unpaid and overdue invoice counts and amounts, an overdue rate, and total outstanding. Below organization administrator this card says the figures are administrator-only rather than showing zeros.

Walkthrough — generating and downloading a report

MSP path: MSP portal → Reports (/msp/reports) Organization path: Organization portal → Reports → Exports (/org/reports, Exports tab, organization administrator and above)

  1. Pick a report type from the catalogue cards and press Generate. Financial types are not shown at all to roles that cannot run them.
  2. Set the date range. It defaults to the last 30 days. Start must be on or before end.
  3. Narrow to specific clients (MSP portal only). Leave the list empty for every organization the account can see. The selection can only ever narrow that set — a client outside it is dropped at generation time rather than honoured.
  4. Choose a format — PDF, CSV or Excel.
  5. Choose whether to include charts (PDF only). Breakdown sections get a bar chart above the table. The option is not offered for CSV or Excel, and is recorded as off if requested for them.
  6. Press Generate. You get an immediate acknowledgement and a PENDING row in the history; the page polls every five seconds and the row advances to GENERATING, then COMPLETED, on its own.
  7. Download. The button fetches the bytes through the authenticated API and saves the file. It is not a public link — the account is re-checked on every download, and financial types re-check the role.
  8. Delete removes the row from the library, after a confirmation.

The report catalogue

Ten report types map to six aggregators plus one composable type. The pairs (REVENUE/REVENUE_SUMMARY, TICKETS/TICKET_ANALYSIS, ASSETS/ASSET_INVENTORY) run the same aggregation; both names exist for API compatibility, and the UI offers one of each.

TypeSummary figuresTables
REVENUE / REVENUE_SUMMARYInvoices, total billed, total collected, outstanding, collection rateRevenue by client; revenue by status; every invoice
TICKETS / TICKET_ANALYSISTickets, resolved, resolution rate, mean time to resolveBy status; by priority; by client; every ticket
ASSETS / ASSET_INVENTORYAssets, total purchase value, warranty expired, warranty expiring within 90 daysBy client; by type; by status; every asset
CLIENT_HEALTHClients, tickets, SLA breaches, breach rate, billedOne row per client: tickets, open, breaches, breach rate, assets, billed
SLA_COMPLIANCETickets under SLA, response met, resolution met, response breaches, resolution breachesAttainment by client; every breached ticket with its deadlines
PROFITABILITYRevenue, labour cost, gross margin, margin %, unpriced hoursPer client: revenue, hours, billable hours, cost, margin, margin %
CUSTOMThe summaries of every dataset you name, prefixed by datasetThe tables of every dataset you name

Date ranges mean different things per type, because the underlying data means different things:

  • Revenue and profitability filter on invoice issue date.
  • Tickets and SLA filter on ticket creation date.
  • Assets filter on purchase date — an inventory is a stock, not a flow, so a range narrows to kit acquired in that window rather than excluding older kit that is still deployed.
  • Client health filters tickets and invoices by the range; the open-ticket count and asset count are point-in-time.

Profitability costs labour at the rate recorded on each time entry — the rate that applied when the work was done. Entries with no rate are reported as “unpriced hours” and excluded from cost rather than costed at zero, which would overstate margin.

CUSTOM requires parameters.datasets, naming one or more of REVENUE, TICKETS, ASSETS, CLIENT_HEALTH, SLA_COMPLIANCE, PROFITABILITY. An unrecognised name fails the report with a readable reason instead of being silently dropped.


Report options

OptionValuesDefaultEffect
typeThe ten report typesrequiredWhich aggregation runs
titleup to 200 charsper-type defaultThe document heading and the download filename
descriptionup to 2000 charsnoneStored on the row; searchable
dateRangeISO date or date-timeall timeThe reporting window (see per-type meaning above)
clientIdsup to 500 org idsevery visible orgNarrows the scope. Cannot widen it
options.exportFormatPDF, CSV, XLSXPDFWhich renderer runs
options.includeChartsbooleanoffPDF only. Adds a bar chart above each chartable breakdown table. Forced off for CSV and XLSX
parametersfree-form objectnoneType-specific. CUSTOM requires datasets

What “chartable” means

Percentage columns are never plotted — a rate does not share a scale with the counts beside it. Bars are scaled against the largest magnitude in the set and every bar prints its own number, so the chart cannot imply a magnitude the data does not support.

In practice this charts the breakdowns (“By status”, “By priority”, “By client”, “By type”) and leaves the long raw listings as tables.


Report lifecycle

  • A report is never left silently pending. A generator that throws marks its row FAILED with the error message and counts into the job’s error total.
  • Two sweeps cannot render the same report. Each row is claimed with a conditional PENDING to GENERATING update; a row whose claim affects nothing was taken by the other sweep and is skipped.
  • rowCount: 0 on a COMPLETED report means “no data matched”, not “the generator broke”. Both portals say so on the row.
  • Scope is resolved at generation time, from the report’s own account — not from the request, and not at queue time. A report queued before a client was detached cannot widen back into it later.
  • The batch is bounded at 10 per sweep. A tenant that queues two hundred reports does not monopolise the worker; the next tick picks up the rest.

Analytics tabs (organization portal)

/org/reports also carries five live analytics tabs alongside the Exports tab.

TabSourceVisible to
OverviewOrganization executive statspower user and above
Tickets & SLATicket statisticspower user and above
Billing & FinanceInvoice and contract statisticsorganization administrator and above
AssetsOrganization executive statspower user and above
Time TrackingTime-entry statisticspower user and above
ExportsThe report libraryorganization administrator and above

The period selector in the header drives the Tickets & SLA and Time Tracking windows (as a day count) and the Overview and Assets windows (as a named period). Billing & Finance is month-to-date / year-to-date and does not move with it.


The platform dashboards

Paths: /platform/executive and /platform/reports, both platform-admin only.

/platform/executive shows account totals and status mix, platform MRR with its active/trial split, install-wide SLA attainment, ticket and change workload, alert severity, unbilled time, and the organizations with the most escalations and alerts.

/platform/reports is a four-tab read of the same install-wide aggregate: Overview, SLA & Operations, Revenue, Accounts.

Platform MRR is realized, not estimated. It sums PlatformSubscription.monthlyAmountCents across active and trialling subscriptions — the amount the billing engine actually bills, including seats, billing cycle and per-account price overrides.


Reporting windows

What the window does and does not move:

Moves with the periodPoint-in-time regardless
SLA attainment (tickets resolved in the window)Open, urgent, unassigned and breached counts
Resolved escalations, recent escalation listActive and pending escalations
Average resolution time and its sample sizeAsset totals, alerts, warranty expiries
Invoice unpaid/overdue totals
Client counts and MRR

How every number is derived

The ones worth stating explicitly:

FigureDerived from
SLA rate with no samplenull, rendered as “No data”. Never 100%, never 0%
Client MRROrganization.mrr summed across client organizations
MRR growthToday’s client MRR against the most recent AccountMrrSnapshot on or before roughly one month ago, written daily by the account-mrr-snapshot job. null when there is no prior snapshot — “not enough history”, not 0%
Platform MRRPlatformSubscription.monthlyAmountCents over ACTIVE and TRIAL
Average resolution timeA database-side average of resolvedAt - createdAt across every ticket resolved in the window, with its sample size. null when nothing was resolved
SLA compliance rate (reports page)Counted over tickets whose SLA outcome is KNOWN — breached, or responded and resolved, or finished. Tickets still inside their target are excluded from both the numerator and the denominator, and appear in the at-risk counter instead
Realized revenue (MTD, YTD, monthly trend, collection rate)SUM(payment.amount - payment.refundedAmount) over succeeded, partially-refunded and refunded payments. Refunds are subtracted by amount, so a partial refund reduces the figure rather than erasing the payment; uncaptured payments do not count at all
Unpaid / overdueInvoice.status grouped; SENT, VIEWED, PARTIAL and OVERDUE count as unpaid, OVERDUE also counts as overdue
Assets with alertsActive assets with at least one ACTIVE or ACKNOWLEDGED monitoring alert. Alerts arrive from a connected monitoring integration; with none connected this is legitimately 0
Warranty expiringActive assets with warrantyExpiry between now and 30 days out (90 days in the asset report). Warranty dates come from manual entry or CSV import — RMM discovery does not populate them, so a fleet built purely from discovery reports 0 here
EscalationsTicket.isEscalated for counts; TicketEscalation rows for the recent list
Unbilled timeTimeEntry with no invoice and isBillable
Labour cost (profitability)Each entry’s own hourlyRate multiplied by its duration. Entries with no rate are reported as unpriced hours and excluded

Plan tiers

The report library carries no plan gate. Every report type, format and option is available on every tier including Free, for both MSPs and end customers. So is the organization executive dashboard.

The MSP cross-client roll-up is gated on the rollUpReporting entitlement:

LevelWhat it unlocks
off/msp/executive returns an upgrade offer
BASICThe operational roll-up: tickets, SLA, assets, escalations, clients
FULLAdds the financial roll-up: MRR, growth and top clients by revenue
TierrollUpReporting
MSP Free / Starter / Growthoff
MSP ScaleBASIC
MSP EnterpriseFULL
Customer Free / Essentials / Professionaloff
Customer BusinessBASIC
Customer EnterpriseFULL

Platform administrators bypass the gate. An account with no resolvable tier is not blocked — the same fail-open-on-unresolved rule every other gate in the product uses.


Troubleshooting

What you seeCause
Insufficient roleYour role is outside the report or dashboard role set. power user and CUSTOMER cannot use the report library at all.
<TYPE> reports expose account-wide financials and require an administrator roleA technician tried to generate or download Revenue, Revenue Summary or Profitability.
Cross-organization roll-up reporting isn't included in your current plan.The account’s tier has rollUpReporting off. The response carries the upgrade offer and the page renders it.
Date range start must be before endStart is after end.
Invalid date rangeA date failed to parse.
Report is not ready (status: pending) / (status: generating)The sweep has not produced the artifact yet. The library polls; wait for the row to flip to Completed.
Report generation failed: <reason>The row is FAILED; the reason is shown on the row and repeated here. Retry re-opens the generate dialog for the same type.
A CUSTOM report needs parameters.datasets — e.g. {"datasets":["REVENUE","TICKETS"]}A CUSTOM report was queued without naming its datasets.
Unknown dataset(s): <x>. Available: ...A CUSTOM report named a dataset that does not exist. It fails loudly rather than quietly omitting a section you asked for.
Report not found (404)The report belongs to another account. Reports are scoped by account in the same query as the id, so another tenant’s report is indistinguishable from one that does not exist.
A report completes with “No data matched this range or client selection.”rowCount is 0. The generator worked; nothing fell inside the range or the client selection.
SLA rings show “No data”Nothing SLA-tracked was resolved in the window. This is the honest answer; the product will not show a green 100% for an unmeasured population.
MRR growth shows ”— MoM”There is no AccountMrrSnapshot from roughly a month ago yet. Growth becomes available once the daily snapshot job has a month of history.
Revenue shows ”—” with “Requires an MSP administrator”Your role is below MSP administrator. This is not a plan problem and no upsell is shown.
Outstanding shows ”—” with “Administrators only”Your role is below organization administrator. Receivables are administrator data.

Limits and known behaviour

  • A report section is capped at 5,000 rows. A truncated table says so, in every format. Narrow the date range or the client selection for full detail.
  • Charts are PDF only. Requesting them for CSV or Excel records the option as off; the API will not report back a setting it did not honour.
  • Deleting a report removes the row, not the bytes. The stored file is left to the exports container’s lifecycle expiry rather than deleted inline, so a failed blob delete cannot leave you looking at a report you just deleted. The file is unreachable either way — downloads go through the row.
  • There is no report scheduling. Reports are generated on request. There is no recurring or emailed report.
  • Dashboards are not exportable as a document. To hand a number to someone outside the product, run the matching report.
  • The MSP client picker offers managed clients only. The default (nothing selected) covers every organization in reach, including the MSP’s own, but you cannot select your own organization as an explicit filter.
  • The reporting period does not apply to report artifacts. Reports carry an explicit date range chosen in the generate dialog.
  • Reporting is not available in the customer portal or on mobile.
  • Warranty exposure depends on warranty dates being present. Assets created by RMM discovery carry no warranty date until someone enters one or imports it, so “warranty expiring” reports 0 on a discovery-only fleet. This is an absent input, not a broken metric.
  • Alert counts depend on a connected monitoring integration. With none connected, alert figures are legitimately zero.
  • SLA compliance excludes work still inside its target. A ticket that has not breached and has not been resolved is neither met nor missed; it appears in the at-risk counter instead. This is why compliance can be “No data” on a busy desk that has simply not closed anything in the window yet.
  • REVENUE/REVENUE_SUMMARY, TICKETS/TICKET_ANALYSIS and ASSETS/ASSET_INVENTORY are aliases. Each pair runs identical aggregation; the UI offers one name from each pair.

Questions this guide did not answer?

Ask us. You will get a reply from someone who uses the product every day.

Book a demo Contact us

A 30-minute walkthrough against your own workflow. No slides.