Once the connector is hooked up you can ask questions in English and get numbers back in a few seconds. What’s our cash position. Which sales orders are past their promised ship date. Top ten vendors by spend this year. No SQL, no knowing which table anything lives in.
It’s good. I use it most days.
It’s also wrong often enough that you need a habit, not just a connection. Two different things cause it, and they aren’t related to each other.
Your answer is true for your role, not for the account
Every query runs under your NetSuite role, with your permissions and your restrictions. That’s by design and it’s the right design. Oracle’s docs are explicit about it, and the preconfigured CFO, Controller, AR and AP Analyst and Treasury roles exist so AI access inherits permissions people already have.
The problem is that an empty result and a forbidden result look exactly the same in a chat window.
Nothing tells you 3,400 rows were filtered out. You get what your role can see, and the model describes it like it’s the whole picture.
Here’s the one that made this real for me. Net item sales.
Our customer service role can see sales orders, invoices, cash sales, item fulfillments and return authorizations. It can’t see item receipts. The customer service manager role sees item receipts too.
Both of them ask for net item sales. They get different numbers, and the manager’s is lower, because item receipts are what brings returned product back in and the rep’s number never subtracts them.
So the person with less access gets the better-looking number. Neither query is wrong. Nobody made a mistake. And the one who’s most likely to repeat it in a meeting is the one whose number is too high.
That’s the shape to watch for. It isn’t just “you might see fewer rows.” A missing record type in the middle of a calculation quietly changes what the answer means.
A query that comes back empty has the same problem in a smaller way. It reads as “we don’t have any of those” when it means “you can’t see any of those.”
The quieter version is a total that comes back looking completely normal. If your role is restricted by subsidiary, department, class, location or a custom segment, every number you get is already scoped to those, and nothing in the answer says so. A revenue figure can be exactly right for what you’re allowed to see and still not match what the CFO has.
The tools are also role-gated. A tool only shows up in your client if your role has every permission it requires. Record tools need REST Web Services (Full), saved search tools need Perform Search (View). Two people on the same connector can have different toolboxes, and the one who can’t create records probably doesn’t know creating records was ever an option.
Two habits help.
When I hand somebody an AI-generated number now, I say which role I ran it under. That heads off most of the “why don’t our numbers match” conversation before it starts.
And when a result looks wrong, check permissions before you check the query. Would your role return those rows in a saved search? If not, the SQL was never the problem.
There’s also a decision to make here and I don’t think there’s a right answer to it. You can run the connector under one dedicated reporting role with broad read access so everybody’s numbers reconcile, or keep it scoped per person and treat the differences as the security model doing its job. I lean toward the second for anything with real restrictions on it, but I can argue myself out of that.
You filtered in the chat instead of in the query
You ask for all the sales orders, it runs a broad query, and then you narrow down in conversation. “Okay now just the open ones from last month over ten thousand.” It feels like the natural way to work. It’s where a lot of the wrong answers come from.
A single SuiteQL result maxes out at 5,000 rows without pagination, and the tooling pages in chunks below that. So if your unfiltered query would have returned more than what actually reaches the model, everything it filters afterward is filtering a piece of your data. You get a total that looks fine. Nothing in the answer tells you anything got cut off.
Even under the cap, a WHERE clause is exact and “please only count the open ones” is an instruction to a language model. For a number I’m putting in front of a controller I want the first one.
So I push every filter I can into the query and use the chat to decide what to ask, not to clean up what came back.
You don’t have to write the query
Nobody is suggesting you learn SuiteQL. What you can do is ask for the filtering to happen in the query rather than afterward, and that’s a sentence.
Instead of “get me the sales orders,” then “now just the open ones since June,” ask for it in one go. Something like: count the sales orders still pending fulfillment dated since June 1, 2026 and total them, and do the filtering in the query, not on the results.
Then the check, which costs nothing and needs no SQL from you. Ask it to show you the query it ran. You don’t have to be able to write one to see whether what you asked for is in it. What you want to see is a WHERE clause with your filters in it and the counting done in the query, like this:
sql
SELECT COUNT(*) AS cnt, SUM(foreigntotal) AS total_value
FROM transaction
WHERE type = 'SalesOrd'
AND status = 'SalesOrd:B' -- pending fulfillment
AND trandate >= TO_DATE('2026-06-01','YYYY-MM-DD')
The database did the filtering and the counting and the summing, so the single row that comes back is the answer. There’s nothing left for the row cap to cut off.
What you don’t want to see is a broad SELECT with no filters, followed by the model telling you it counted the open ones itself. That number is built on whatever fit.
Check that status code against your own account before you trust it. SalesOrd:B is the common value for pending fulfillment but I wouldn’t swear to it everywhere.
One thing about that query while we’re here. It’s asking what’s pending right now out of the orders placed since June, which is a fair question. If I’d meant “what was pending at the end of May” it would be wrong, for the reason in the next section.
Ask to see the logic before you use the number
Ask for total revenue and there’s a good chance you get sales orders, because “sales” is in the name and orders are the thing everybody talks about. Sales orders don’t post. They aren’t revenue. Revenue is invoices and cash sales.
So the first thing I do now is make it tell me what it’s about to query.
Me: Total revenue for May.
Claude: I’ll sum sales orders dated in May.
Me: Sales orders aren’t revenue, they don’t post. Use invoices and cash sales.
That’s a thirty-second exchange and it’s the difference between a number I can defend and one I can’t. It’s also a bigger error than it looks. It isn’t a wrong filter, it’s the wrong record type, so no amount of tightening the date range would have caught it.
If you want revenue net of returns you need credit memos in there too. Worth saying out loud rather than assuming, because “net” means different things to different people in the same meeting.
Status tells you now, not then
This one is easy to miss and I’ve been caught by it.
If you do go to orders for something, status is a current-state field. It doesn’t remember what it was. Ask in June how many orders were pending fulfillment at the end of May and you’ll get today’s statuses filtered by a May date, and everything that shipped in June has already moved on. The number comes back clean and it’s answering a question you didn’t ask.
Anything where you mean “as of a date in the past,” check whether the field you’re filtering on actually holds history. Most don’t. Dates do, statuses don’t.
The assumptions that keep coming up: cancelled, voided and draft records included when I didn’t want them. Internal IDs instead of labels, so I get 13 where I expected Open. Duplicates counted when I asked for unique, which is almost always a transaction line join, that one’s covered properly on the SuiteQL page. And “this month” meaning something different to the model than it does to me, because calendar month and rolling 30 days and my fiscal period are three different answers.
One more that’s easy to miss because it happens underneath the conversation. Tool calls get validated, and when a required parameter is missing the client may ask you for it or it may fill in a default and carry on. A default date range or a default subsidiary you never picked gives you a correct answer to a question you didn’t ask. If something looks subtly off rather than obviously wrong, that’s worth ruling out.
There are interactive panels that help with this. The Standard Tools SuiteApp ships a Report Filters app and a Record Selector app, and when you’re using one, the filters are values you clicked rather than values inferred from a sentence. That part is solid.
Two of them are meant to come up on their own, which is the part that matters. Report Filters is documented for use when you haven’t specified all the parameters a report needs, and Record Selector for when you haven’t named the record. So the moment you didn’t think to be specific is the moment they’re built for. The Prompt Library is the exception, and that one you open by asking for it.
The limit worth knowing: that’s guidance to the AI client, not a gate inside NetSuite. Nothing stops a client from skipping the panel and running the report on its own guess at your subsidiary and your period. It’s a good nudge and it isn’t a control.
We tested all three in two clients, and one of them doesn’t work at all. That’s a page of its own: NetSuite MCP Apps, and why yours might come up empty.
And for anything that matters, ask for the number broken into pieces so you can check one piece, then go spot-check a customer or a vendor in NetSuite.
Where it’s actually good
Laying out the failure modes first makes this sound riskier than it is. For operational questions the speed is real and the accuracy is fine.
My Friday check used to be five reports, copy the numbers into a spreadsheet, add the formulas, write a summary. AR aging by bucket, AP due in the next 7 and 8-30 and 30+, DSO (days sales outstanding), whether the bank accounts are reconciled, anything that hasn’t been touched in 30 days. Two hours. Now it’s one saved prompt and about fifteen minutes, most of which is me reading it.
Where I draw the line: operational questions I trust and move on. Do we have enough cash to cover payroll, who owes us the most, are we ahead of forecast.
Anything that posts or closes or ends up in a financial statement, I verify. Journal entries, the close package, board numbers, anything a customer or an auditor sees.
That’s not really a limitation of the AI. It’s the same rule I’d apply to a report a new analyst handed me.
Want help setting the guardrails for your team? The first hour is free. We’ll look at how your roles are scoped and what people are actually asking.
