The REST API and BQL (Business Query Language) solve overlapping but different problems. REST is how something outside the Acumatica instance reads or writes data. BQL is how code running inside the Acumatica application — a customization, a graph extension, a Generic Inquiry — queries the database directly. Confusing the two leads either to unnecessary customization code or to slow, chatty integrations.
Two different vantage points
REST calls happen from outside the process — a separate client application, over HTTP, subject to network latency and (for writes) the full save pipeline of the target screen. BQL runs in-process, inside the same application domain as the graph it's querying, compiled against the actual DAC types. That difference in vantage point is really the whole answer to "which one should I use": if the code lives inside an Acumatica customization project, BQL is almost always both faster and more capable; if it lives outside, REST is your only real option.
When REST is the only choice
Anything running outside the Acumatica instance — a separate .NET service, a Node.js middleware layer, a no-code automation tool, a mobile app — has no way to run BQL directly. REST (or the older SOAP contract) is the only supported door in from outside. This isn't a preference; it's the actual boundary of what's reachable from outside the process.
When you're inside a customization, choose BQL
If you're writing a graph extension, an event handler, or a processing screen that runs inside Acumatica itself, reaching out to your own instance's REST API from inside a customization is almost always the wrong call — it adds HTTP round-trip latency and re-runs the full save pipeline for something that could query or update directly through PXSelect/BQL in the same process, with direct access to the DAC's actual field types rather than a JSON-serialized approximation of them.
It's seen in the wild more often than it should be — a graph extension making an HTTP call back into the same instance's REST endpoint to read data it could have queried with BQL in the same request. It works, but it's strictly slower and more fragile (auth tokens, network hiccups, serialization) than staying in-process.
Query power and limits
BQL gives you real joins, aggregates, and the full expressiveness of a query against the underlying DACs — closer to SQL than REST's flatter $filter/$expand OData-style querying. REST's query parameters cover common filtering and paging well, but for a genuinely complex multi-table aggregate query, a Generic Inquiry (itself backed by BQL) exposed as a REST-queryable entity is usually a cleaner answer than trying to force the equivalent logic through nested $expand and $filter parameters from outside.
A simple decision rule
Ask where the code physically runs. Inside the Acumatica application process (a customization project) — BQL. Outside it, in a separate service or tool — REST. The one exception worth naming: a Generic Inquiry is a bridge between the two, letting BQL-level query power be exposed as a REST entity for external consumers without them ever touching BQL directly.
Wrapping up
REST and BQL aren't competing choices for the same job — they operate on opposite sides of the process boundary. Use BQL for anything running inside a customization, REST for anything outside it, and lean on Generic Inquiries when an external consumer needs query power BQL has but REST's flat filtering doesn't.
Independent software engineer in Nairobi specialising in Acumatica customisations, Laravel backends, and tax fiscalisation integrations across East and Southern Africa.