> ## Documentation Index
> Fetch the complete documentation index at: https://docs.usestatemachines.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Query records with SOQL

> Run SOQL queries, follow result pages, and inspect deleted records under the chosen actor.

Use SOQL to inspect test data and verify integration outcomes. Connect with the actor your integration uses, then [discover its objects and fields](/apps/salesforce-records).

## Run a query

Send a `GET` request to `/services/data/v{version}/query` with the SOQL statement in the `q` parameter. Replace `{version}` with a served API version. URL-encode the statement through your client's query-parameter API.

For example, query the account from the record guide:

```sql theme={null}
SELECT Id, Name, Description
FROM Account
WHERE Name = 'Juniper Sample Company'
ORDER BY Id
```

Inspect `totalSize`, `done`, and `records` in the JSON response. A successful query with no matches returns an empty result. That result may also reflect the actor's record visibility.

Use `ORDER BY` when a test depends on row order. Add a unique tie-breaker such as `Id` when your primary sort field can have duplicate values. A query without an explicit order is unsuitable for an assertion about which row comes first.

## Follow every result page

After processing `records`, check `done`. If it is false, request the returned `nextRecordsUrl` through the same authenticated client and process that page. Repeat until `done` is true.

Keep the actor and app connection unchanged while following a locator. Do not rebuild the query with increasing `OFFSET`, append the original `q` to locator requests, or infer completion from a short page.

The replica binds each locator to the user who ran the query. Locators expire two days after the query opens. An invalid, expired, or other user's locator returns `INVALID_QUERY_LOCATOR`. Restart the query when your application can safely do so.

A page holds up to 2,000 records. To change that, send `Sforce-Query-Options: batchSize=N` with N from 200 to 2,000.

For assertions over changing data, complete one query's pages before making further writes. The locator does not add records inserted after it opens. Ordinary query pages omit records deleted between pages, while `totalSize` stays unchanged. A locator is not an immutable copy of every record value.

## Query relationships

Use describe's relationship names. A lookup field name and the corresponding relationship name are different request values.

To read a contact's parent account, use a parent path:

```sql theme={null}
SELECT Id, LastName, Account.Name
FROM Contact
WHERE LastName = 'Example'
ORDER BY Id
```

To read contacts under an account, use the child relationship name:

```sql theme={null}
SELECT Id, Name, (SELECT Id, LastName FROM Contacts ORDER BY Id)
FROM Account
WHERE Name = 'Juniper Sample Company'
ORDER BY Id
```

Inspect each parent's nested result rather than treating child records as top-level rows. REST and SOAP accept up to four nested child levels from API version 58.0 and one level below it. Bulk query jobs accept none.

## Aggregate records

For a count, use `SELECT COUNT() FROM Account`. Read the count from `totalSize`. `COUNT()` does not produce a normal record list.

For grouped results, select the group field and an aggregate:

```sql theme={null}
SELECT Industry, COUNT(Id)
FROM Account
GROUP BY Industry
```

Check that describe marks the grouping field as groupable. Select only fields that are grouped or aggregated. A grouped or aggregate result larger than one page fails with `EXCEEDED_ID_LIMIT`. Add `LIMIT` to keep it on one page.

## Inspect deleted records

Send the statement to `/services/data/v{version}/queryAll` to include deleted and archived records. For a deleted test account, select `Id`, `Name`, and `IsDeleted` with a filter on its returned ID.

Follow `nextRecordsUrl` as returned even when it uses `/query/`. The locator retains the original queryAll behavior. Ordinary `/query` omits deleted records.

## Diagnose query failures

Inspect `errorCode` and `message` before retrying. Confirm the object, field, and relationship names against describe for the same actor and API version.

The replica supports selected SOQL filters, parent paths, child queries, grouping, aggregates, date literals, and semi-joins. It returns `MALFORMED_QUERY` with the message `<feature> is not supported` for `FOR UPDATE`, `UPDATE TRACKING`, `UPDATE VIEWSTAT`, `WITH SYSTEM_MODE`, `WITH DATA CATEGORY`, other `WITH` filters, `DISTANCE()`, `FORMULA()`, and a `FROM` list with relationship aliases. `WITH SECURITY_ENFORCED` also fails. `WITH USER_MODE`, `FOR VIEW`, and `FOR REFERENCE` are accepted and change nothing.

Do not use the `explain` parameter to validate Salesforce query plans. The replica does not implement that behavior. See the [known differences](/apps/known-differences) for other query and permission gaps.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.