Logic API
Queries
Build read-only endpoints that return one record, a full list, or pages of records, with inputs and access control.
A query is a read-only endpoint in a module. It runs a Dataverse query, with the filters, columns and related tables you choose, and returns the matching records to the caller. Use queries for lists and searches, such as “the open cases of a customer” or “active products in a price list”.
Add a query
Section titled “Add a query”- In the tree, open the module and select Queries > Add query.
- Enter the Query Name. It becomes the last segment of the address: query
openCasesin moduleServiceis called atGET /service/opencases. - Choose the Multiplicity (see below).
- Define the query with the Query Builder, or switch to FetchXML and paste a FetchXML query.
- Add a Query Argument for each value callers pass in, and use the arguments in the query’s conditions.
- Set Access Control. See Access control.
- Save with Ctrl+S.
Settings
Section titled “Settings”| Setting | What it does | Notes |
|---|---|---|
| Query Name | Names the query and its address. | 3–50 letters and numbers, starting with a letter. The address is lowercase. |
| Multiplicity | How many records the query returns, and in what shape. | Single, All or Sliced. |
| Query Builder / FetchXML | The table, columns, filters, sort order and related tables. | Build it visually, or use FetchXML you already have. |
| Query Argument | Inputs callers pass on the query string. | Each has an Argument Name and a Type; date and time arguments also have a DateTime Behavior, and choice arguments an Option Set. |
| Access Control | Who may run the query, and when. | Same options as for actions. |
Multiplicity
Section titled “Multiplicity”| Multiplicity | Returns | When nothing matches | Use it for |
|---|---|---|---|
| Single | One record | 204 No Content |
“My profile”, “the account with this number” |
| All | Every matching record, as a list | 200 OK with an empty list |
Short, bounded lists: team members, the statuses of a process |
| Sliced | One page of records, with paging information | 200 OK with an empty page |
Anything that can grow: searches, customer lists, case histories |
Sliced queries accept three extra query-string parameters: page, page-size and cursor. See Calling the API.
How it behaves
Section titled “How it behaves”- Queries are always
GETrequests. Arguments are passed on the query string, for example?customerId=…&priority=1. - An argument that is missing or of the wrong type returns
ARGUMENT_VALIDATION_ERROR. - Callers see whatever the query returns. Use query conditions and user properties to limit callers to their own data. For example, filter cases by the signed-in contact.
- Use All only when the number of results is naturally small. For anything that can grow, use Sliced, so callers never load thousands of records at once.
Example: open cases of a customer, page by page
Section titled “Example: open cases of a customer, page by page”A service portal shows a customer’s open cases, newest first, 20 at a time.
| Setting | Value |
|---|---|
| Module / Query Name | Service / openCases → GET /service/opencases |
| Multiplicity | Sliced |
| Query | Table incident; columns ticketnumber, title, prioritycode, createdon; condition: status is Active and customer equals the customerId argument; sort by createdon descending |
| Query Argument | customerId (Unique Identifier) |
| Access Control | Demand Authenticated User |
GET /service/opencases?customerId=6b1f0c3e-2d4a-4b5c-8e9f-0a1b2c3d4e5f&page=1&page-size=20Authorization: Bearer eyJ0eXAiOi...{ "cursor": "…", "count": 20, "totalRecordCount": 47, "hasMoreRecords": true, "data": [ { "ticketnumber": "CAS-01842-K9T2", "title": "Router drops connection", "prioritycode": 1, "createdon": "2026-10-21T08:14:00Z" }, { "ticketnumber": "CAS-01839-R3M7", "title": "Invoice shows wrong VAT rate", "prioritycode": 2, "createdon": "2026-10-20T15:02:00Z" } ]}