Skip to main content

Working with lists

List fields use Relay-style connections. They return edges, node, and pageInfo so integrations can process large result sets in smaller pages.

query ProductsAfterCursor($after: String) {
products(first: 50, after: $after) {
edges {
cursor
node {
id
productNumber
}
}
pageInfo {
hasNextPage
endCursor
}
}
}

Pagination

Pass first to choose the page size. If pageInfo.hasNextPage is true, pass pageInfo.endCursor as after in the next request.

Filters

Most list fields expose a type-specific filter input. Filters can be combined with AND, OR, and NOT.

query ProductBySku($sku: String!) {
products(filter: { productNumber: { equals: $sku } }) {
edges {
node {
id
productNumber
name
}
}
}
}

Filter operators depend on the scalar type. Common examples are equals, in, contains, before, after, lt, lte, gt, gte, and isNull.

The list operators in and notIn require a non-empty list of values; passing an empty list is rejected as a BAD_REQUEST error. If a filter's value list can end up empty (for example when it is built from an earlier query's results), skip the request instead of sending an empty list.

Synchronization

For recurring synchronization jobs:

  • Store the cursor while processing a page.
  • Request only the fields the job needs.
  • Use filters such as updatedAt where the exposed type supports them.
  • Retry failed pages idempotently instead of restarting a whole export when possible.

List fields in the current 2026-06-unstable API expose pagination and filters. If an integration needs a stable domain-specific ordering that is not represented by the schema yet, add that requirement to the relevant use case before sorting after retrieval.