factQuery filters are a JSON document carried inside one GraphQL string.
Always pass them as a variable so your JSON encoder handles the nested escaping.
Valid filter variables
query ShippedOrders($slug: String!, $filters: String!, $offset: Int!) {
factQuery(
dataModelSlug: $slug
mode: "timeline"
filters: $filters
since: "2026-07-01T00:00:00Z"
limit: 20
offset: $offset
) {
hasNextPage
results { entityId observedAt data }
}
}
{
"slug": "order",
"offset": 0,
"filters": "[{\"field\":\"status\",\"op\":\"eq\",\"value\":\"shipped\"},{\"field\":\"total\",\"op\":\"gte\",\"value\":100}]"
}
Each clause has field, op, and non-null value. field must exactly match
one DataModelField and at most 20 clauses are accepted.
| Field type | Operators |
|---|---|
| String | eq, neq, contains |
| Integer/Float | eq, neq, gt, gte, lt, lte |
| Datetime | eq, neq, gt, gte, lt, lte |
| Boolean | eq, neq |
contains is a case-insensitive literal substring. % and _ in the value
are escaped instead of becoming SQL wildcards.
Invalid filters
These are query errors and must be corrected before retrying:
- malformed JSON in the GraphQL string;
- unknown or non-filterable field names;
- an operator unsupported by the model field type;
- values that cannot cast to the field type;
nullvalues; or- more than 20 clauses.
The error identifies the invalid field/operator where safe. It does not expose arbitrary warehouse payload paths.
Offset pagination
limit defaults to 50, has a hard maximum of 250, and should still be explicit.
Start offset at zero and add the applied limit while hasNextPage is true.
Request count on the first page only when needed.
The 250 maximum is not a throughput promise: complexity often binds first.
Complexity
The default maximum query complexity is 200. A page field selection is
multiplied by the requested limit, so narrower selections permit more rows. A
query selecting several page fields and results { entityId observedAt data }
can exceed the limit at limit: 50; reduce the limit or selected fields.
Do not request fields “just in case.” GraphQL's explicit selection is a cost and data-minimization tool.
Depth, document size, and windows
Default configurable guards are depth 10 and 8,000 parseable tokens. Violations are rejected before resolution. Timeline windows default to 90 days and clamp at 366 days; explicitly bounded smaller windows are easier to operate.
Per-credential rate limiting also applies: 300 requests per 60 seconds by
default, with 429 and Retry-After on breach.
For exact types and response objects, open the factQuery reference.