Reporting
Reporting that reads your live rows, not last night’s copy.
Every business tool eventually promises analytics, and the analytics are usually a nightly copy of your data in a second system that has its own idea of what a deal is. Oneop reports read the same tables the application writes to. An invoice raised two minutes ago is in the invoice report.
Thirty-three datasets across eleven of the twelve modules, sixty-eight reports that already exist, and an engine where the request names a column and the server decides what that column is.
No credit card. Free plan, 2 seats.
33
Datasets you can query, across eleven modules
68
Reports that already exist, before you build one
0
Columns a request can name that the server did not define
8
Datasets a role gate hides rather than refuses
2
Independent guards between a share link and a finance report
Four steps, and only one of them is yours
Pick the question. Everything after that — which tables, which predicates, which joins, which workspace — is decided by the server from a catalogue you cannot edit from a request. Then read it, take it away, or have it arrive on a Tuesday.
- Choose from a catalogue rather than writing a queryThirty-three datasets, each with the dimensions, measures and filters that make sense for it. You are picking from a list, which is why nothing here has ever needed a SQL box.
- The server turns keys into a queryYour report names a measure. What that becomes — the column, the aggregate, the join, the workspace filter on both sides of it — is written in server code and cannot be supplied by the request.
- Read it, or take it with youOn screen, as CSV, XLSX or PDF, or as a link somebody without an account can open. Each of those has a different thing that can go wrong, and each is handled separately.
- Stop asking for itDaily, weekly or monthly, at an hour in a time zone, to a list of people, with the file attached. Every run is recorded — including the runs that failed.
Pick
A dataset, up to two groupings, the measures you wantBuilt server-side
Columns, joins and the workspace filter — none of it from the requestRead or export
On screen, as a file, or as a guarded linkScheduled
In your time zone, with the file attached, every run recorded
What you can ask, and what the engine does with it
Four mechanisms, in the order a question passes through them — including the places where what you can configure and what the server will execute are deliberately not the same thing, and the one place they diverge by accident.
Step 1
Thirty-three datasets, eleven modules, sixty-eight reports already written
The catalogue is the product. Each dataset carries the dimensions you can group by, the measures you can aggregate and the filters that make sense against it — so building a report is choosing, not composing, and there is no query language to get wrong.
Sixty-eight reports already exist across those eleven packs, and running, filtering and exporting them is not a paid feature. The role gate on the last two rows is worth understanding: finance and tax datasets are not shown to a role that cannot query them, so they are absent from the list rather than present and forbidden.
| Pack | Sets | What you can count | Who |
|---|---|---|---|
| CRM | 3 | Deals, leads and contacts — value, stage, source, owner, age | Everyone |
| Sales sequences | 3 | Sequences, enrollments and every individual step result | Everyone |
| Help desk | 3 | Tickets, CSAT surveys and agent performance | Everyone |
| Live chat | 2 | Conversation volume, routing, who handled it, and the rating they left | Everyone |
| AI chatbot | 3 | Conversations, outcomes and message volume | Everyone |
| Inventory | 6 | Items, stock by warehouse, sales orders, shipments, purchase orders, returns | Everyone |
| Projects | 1 | Projects by status, owner, dates and budget | Everyone |
| Automation | 2 | Workflows and every execution, including the ones that failed | Everyone |
| AI workforce | 2 | Agent runs and AI credit usage by agent and by month | Everyone |
| Finance | 5 | Invoices, bills, payments, expenses and vendors | Admins only |
| Tax | 3 | Filings, postings and exemptions | Admins only |
Live chat covers volume, routing, handler and rating. Response time and wait time are not on that row, and the FAQ says why rather than leaving you to find an empty column.
Step 2
Your report names keys. The server owns the query.
A report definition is a set of names — this dataset, these groupings, these measures, these filters. What each of those names becomes is written in server code. The request never supplies a column, an expression, a join condition or a predicate, which is why there is no version of this where a cleverly-shaped report reads something it should not.
The workspace filter is the clearest case. It is not part of the configuration at all, it is applied to the base table on every query, and it is applied again to each joined table separately — so a join cannot become the way around it.
| Control | Set | What the engine does |
|---|---|---|
| Which columns a report can name | Chosen from the catalogue | Enforced — the request sends keys, and the server owns every column, expression and join it turns into |
| Which workspace the rows come from | Not configurable, by design | Enforced — applied to the base table and re-applied to every joined table, and no report config can override it |
| How many things you group by | Up to two at once | Enforced — a third grouping is refused rather than quietly dropped from the result |
| How many rows come back | Per report, 500 by default | Enforced with a 5,000-row ceiling — and when it truncates, the result says it truncated |
| A key the catalogue no longer contains | Only possible on an older saved report | Refused when you run it on screen. Skipped instead on every path that executes a saved copy — export, dashboard tile, share link, scheduled email — so those can come back narrower than the report you are looking at |
| Who can query finance and tax | By role, not by plan | Enforced — and those datasets are not listed to a role that cannot query them, so they are absent rather than forbidden |
Row five is the one to read. It is a real inconsistency between two code paths, and putting it in the same table as the rest seemed better than leaving it out of one.
Step 3
Two AI features, and one constraint they share
You can describe the report you want in a sentence and get a working report configuration back. And a report that has run can come with a paragraph explaining what it shows. Those are the two, they are the same beat, and neither of them is allowed to produce a figure.
Both are metered against your workspace’s AI credits like every other model call in Oneop, so they are visible in your usage rather than free and untracked. How models are governed and constrained across the product is a separate page:AI governance.
Describing a report you want
Describing a report that ran
Step 4
Four ways out, and the thing that can go wrong with each
A report nobody can take anywhere is a report nobody uses. Each route out has its own hazard, and the interesting one is CSV: a spreadsheet treats a cell beginning with an equals sign as a formula, which makes any export a way to carry executable content into somebody else’s machine.
So those cells are neutralised before the cell is quoted rather than after — the order matters, because the character prepended is itself part of the value the quoting is supposed to protect.
| Format | Best for | What we do about it |
|---|---|---|
| CSV | Feeding a spreadsheet or another system | A cell starting with = + − or @ is neutralised before it is quoted, so a report cannot carry a formula into someone else’s spreadsheet |
| XLSX | Handing to somebody who will keep working in it | Real typed cells and column headers, not a renamed CSV |
| Attaching to something, or filing it | Rendered server-side, so it looks the same to everyone who opens it | |
| A link | Showing one report to somebody without an account | A random token, stored hashed, optionally expiring — and finance and tax reports are refused a public link twice over |
And then stop asking for it
Daily, weekly on a day you pick, or monthly on a date, at an hour in a time zone, to a list of people. The email carries the first fifty rows inline so it is readable on a phone, a link through to the live report, and the whole thing attached as a PDF, an XLSX or a CSV.
Two behaviours are worth knowing in advance. If the attachment fails to render, the email still goes, with the inline digest and without the file — a late report beats a silent one. And every run writes a history row whether it succeeded or not, with the error attached when it did not, so a schedule that has quietly stopped producing anything is visible rather than merely absent.
The cadence is worked out by stepping through calendar dates in your time zone rather than by adding a fixed number of hours, so a Tuesday 9am report stays at 9am across a daylight-saving change instead of drifting to 8am for half the year.
When
What arrives
What is written down
Connected with Oneop
There is nothing to connect, because there is nothing to copy
Reporting is not an integration with the rest of Oneop — it reads the same tables everything else writes to. The deal in your pipeline report is the deal on the deal page. The invoice in the AR ageing is the invoice you sent. Stock, tickets, projects, sequence step results and AI credit usage are all queryable the same way, with the same workspace filter, on the same run. That is the difference between reporting inside the business system and reporting alongside it: no extract, no sync window, and no second definition of what a customer is.
- CRMCustomer and commercial context follows the work.
- Help deskSupport sees the customer, commercial and operational history.
- Project managementSold work becomes delivery without rebuilding customer context.
- Inventory & warehouseSales and operations work from the same product and order context.
- FinanceOperational transactions continue into financial records.
The other 6 modules sit on the same record, and reach Reporting the same way:
- Live chatConversations become part of customer context.
- SequencesOutreach works from CRM and customer context under controlled automation.
- AI chatbotAI responds using permitted business context.
- AI agentsAI acts on the same records people do, under limits that are published rather than described.
- AI governanceWhatever AI touches in any other module is metered on the same path first.
- AutomationA trigger in one module can act in another without an integration between them.
Beyond the four
Dashboards are saved reports, pinned
A dashboard tile is a report you already have, laid out on a grid you drag. There is no second query language and no separate dashboard data source, so a tile and the report it came from can never disagree with each other about a number.
A calculated column, without a second tool
Margin as a percentage of revenue, average value per deal, a ratio between two measures you already selected. The expression is built from keys the catalogue defines rather than typed as free text, which is the same reason nothing else here can reach the database directly.
Every run is written down
A scheduled run records what it produced and how many rows, and it records the failures too, with the error attached. A report that silently stopped arriving is one of the easier ways to make a business quietly wrong, so the history exists whether the run succeeded or not.
A report is a thing you can clone
Copy one of the sixty-eight, change the filter, keep it. Reports you save are yours until you share them with the workspace, and the run route enforces that rather than the list simply hiding them.
Time zones are resolved properly, not approximately
A schedule set for 9am Tuesday in Lisbon steps through calendar dates in that zone rather than adding a fixed offset, so it does not drift by an hour twice a year. Small thing. It is also the exact bug that makes people stop trusting a Monday morning report.
Exports and dashboards read the same rows the app writes
There is no nightly copy and no warehouse to fall behind. A report you run at 11am counts the invoice raised at 10:58, because it is reading the invoice table rather than something derived from it overnight.
The two features in step three are the only AI in reporting. How models are metered, constrained and governed across Oneop is one page:AI governance.
Reporting has no integrations, and that is the point
There is nothing to connect reporting to — it reads Oneop’s own tables. What the integrations below do is fill those tables: deals synced from HubSpot, orders from WooCommerce, payments through Stripe, leads captured on WordPress, meetings from a calendar. Once a row is in Oneop it is reportable the same afternoon, with no modelling step in between.
See all integrations- HubSpot
- WooCommerce
- Stripe
- WordPress
- Gmail
- Microsoft 365
- Google Calendar
- Webhooks
For the technical evaluator
The AI writes the sentence. It never writes the number.
Three independent layers, because a model that is merely instructed not to invent something is not constrained — and one honest limit, named below rather than left for you to find.
The three layers, and the limit
Layer one — it can only emit names. When you describe a report you want, the model’s entire output is a set of keys: which dataset, which groupings, which measures, which filters. It is not writing a query, it is not writing an expression, and it is not writing a column name of its own invention — the prompt tells it not to invent keys, and an unrecognised dataset is rejected outright before anything else is looked at. On its own an instruction is not a constraint, which is why it is the weakest of the three.
Layer two — the same validation a hand-built report goes through.The model’s output is parsed against the identical schema that validates a report you built by clicking, with no separate lenient path for machine-generated configurations. Anything structurally wrong is a validation failure at that point rather than something that reaches the engine. On its own this is still not enough, because a configuration can be structurally valid and still name a measure that does not exist.
Layer three — the engine refuses unknown names. AI-built reports are executed in the mode that throws on an unrecognised dataset, grouping, measure, calculation, filter or join rather than skipping past it. This is the layer that matters, because it does not depend on the prompt being well written or the schema being exhaustive: a name the catalogue does not contain cannot become part of a query, so the worst outcome of a hallucination is an error message. It never becomes a number on a screen that somebody then makes a decision with.
And the narrator works from the other end. When a report is narrated, the report has already run: the engine computed the figures, and the model is given those figures and asked to describe them. It is not asked what the number is, so there is no path by which it could answer wrongly — the worst case is prose you disagree with, sitting above a table you can read yourself.
The limit. None of this makes the model’s interpretation of your sentence correct. It can build a valid report that answers a different question from the one you meant — the wrong date range, a filter you did not intend, a grouping that hides the thing you were looking for. That is a real failure mode and it is not defended against here, which is why the configuration it built is shown to you as a report you can inspect and edit rather than as an answer. The guarantee is narrower than “the AI is right”, and narrower on purpose: it is that the AI cannot produce a figure your data does not support.
Why this is the guarantee we surface. Because a wrong number is the failure that survives. It gets pasted into a board deck, quoted in a meeting and budgeted against, and by the time anyone checks, three decisions have been made on top of it. Every vendor in this category is now shipping natural-language analytics, and almost none of them will tell you where the number came from. The answer worth having is not “our model is careful”; it is that the model was never in the path that produced it.
What it costs
The first row is the one worth noticing: running, filtering and exporting the sixty-eight built-in reports works on every plan, free included. The four rows below it are genuinely server-checked rather than hidden menu items — the API refuses them on a plan that does not include them, so there is no arrangement of the interface that gets you the feature anyway. Building your own reports and dashboards comes in on Pro; scheduled delivery and the plain-English builder on Business.
See full pricing| Plan | Run and export the built-in reports | Build your own reports | Dashboards | Scheduled delivery by email | Ask for a report in plain English |
|---|---|---|---|---|---|
| Free $0 | Included | Not included | Not included | Not included | Not included |
| Starter $19 | Included | Not included | Not included | Not included | Not included |
| Pro $59 | Included | Included | Included | Not included | Not included |
| Business $129 | Included | Included | Included | Included | Included |
Frequently asked
Can I get a report on my data without upgrading?
Yes, and this is worth stating plainly because most tools in this category answer no. Sixty-eight reports already exist across eleven of the twelve modules, and running one, filtering it and exporting it works on every plan including the free one. What your plan changes is whether you can create new report definitions of your own, whether you can build dashboards out of them, whether they can be emailed to people on a schedule, and whether you can ask for one in plain English. Those four are real server-side checks rather than a hidden menu item — the API refuses them, so there is no version of this where a workaround gets you the feature. The reason the split falls there is that reading your own data should not be a paid feature, and the machinery that runs a report on a timer for a list of people genuinely is one.
How do you stop a report reading another workspace’s rows?
The workspace filter is not part of the report configuration, which is the whole answer. It is a condition the engine builds from the dataset definition itself, applied to the base table on every single query, and applied again separately to each joined table — so a report that reaches across into contacts, or into a warehouse, gets the same filter on the far side of the join rather than trusting the relationship to have carried it. Nothing you can put in a report definition can remove it, override it or widen it, because the definition never gets to describe the predicate; it only names dimensions, measures and filters from a catalogue the server wrote. That is a stronger property than validating requests carefully, because it does not depend on the validation being right.
What exactly can the AI do, and what can it not do?
It can turn a sentence into a report configuration and it can write a paragraph about a report that has already run. It cannot produce a number. Those are two features and they share one constraint. When you describe a report you want, the model is only ever allowed to emit keys that the catalogue already defines — dataset, dimensions, measures, filters — and it is told not to invent them. Its output is then validated against the same schema a hand-built report goes through, and executed in the mode that throws on anything unrecognised rather than skipping it. So a hallucinated column does not produce a wrong report; it produces a validation error, and never becomes a query. The narrated digest works from the other end: the report runs first, the figures are computed by the engine, and the model is given those figures to describe. It is not asked what the number is. Both are metered against your workspace’s AI credits like every other model call in Oneop, so they appear in your usage rather than being free and untracked, and how models are governed across the product is one page: AI governance.
What can I report on for live chat?
Conversation volume, and how it breaks down: by status, by source, by department, by priority, by which agent handled it, and by hour of day or day of week — plus the satisfaction rating customers left and how many of them rated at all. What you cannot currently report on is response time or wait time, and we would rather tell you that here than let you find it as an empty column. The reason is specific: the table those figures would come from is defined in the schema but is not written to by anything in the product yet, so a chart built on it would be a convincing-looking flat line rather than a measurement. It is an open engineering ticket, not a design decision. Help-desk tickets are a different story — first-response and resolution times there are stamped against a real SLA clock and are fully reportable.
What arrives when I schedule a report?
An email, at the hour you chose in the time zone you chose, containing the first fifty rows laid out inline so it is readable on a phone, a link through to the live report, and the whole thing attached as a PDF, an XLSX or a CSV depending on which you picked. The cadence can be daily, weekly on a given day, or monthly on a given date, and it is worked out by stepping through calendar dates in your time zone rather than by adding a fixed number of hours — which is the difference between a Tuesday 9am report that stays at 9am and one that quietly becomes 8am for half the year. Two behaviours worth knowing. If the attachment fails to render for any reason, the email still goes out with the inline digest rather than being held back, because a late report is better than a silent one. And every run is recorded whether it worked or not, with the error if it did not, so a schedule that has stopped producing anything is visible rather than merely absent.
Can I share a report with somebody who does not have a login?
Yes, with a link, and with two limits that are not negotiable. The link carries a random token that is stored hashed rather than in the clear, so the stored form is not the usable form; you can give it an expiry date; and the public route is rate-limited independently of everything else. The limit that matters more is what can be linked at all: finance and tax datasets are refused a public link when you try to create one, and refused again at the moment somebody opens one, the second check written specifically to cover links that might have been created before the first check existed. Belt and braces on purpose, because the failure being defended against is a ledger report on the open internet with a guessable URL, and that is not a failure you get to fix afterwards.
Do I need a data warehouse or an ETL job for any of this?
No, and not needing one is most of the argument for reporting living inside the business system rather than beside it. Reports read the same tables the application writes to, so there is no extract step, no scheduled sync, no staging copy and nothing that can be six hours behind. An invoice raised two minutes ago is in the invoice report. The trade-off is real and worth naming: this is operational reporting against live data, with a five-thousand-row ceiling per run and up to two groupings, not a modelling layer for a year of transactions across joined-up historical snapshots. If you genuinely need that, you need a warehouse and you should have one. Most businesses asking "how many deals did we close last quarter and who owns the open ones" do not.
Answer it from the same rows that produced it.
Run a report against data you already have. Or book a walkthrough and we will show you a report refused for naming a column that does not exist, a capped result saying it was capped, and a narrated digest written over figures the engine computed.
Free forever · 2 seats · No credit card