Pulse Intelligence

Pagination and enumeration

How limit/offset/sort work across the API, and how to walk the full company or asset universe

Several /v1/ endpoints return more rows than fit in one response. This guide covers the one pagination convention they all share, how sorting interacts with paging, and how to enumerate the entire company or mining-asset universe with an empty filter list.

Which endpoints paginate

Endpointlimit range (default)Notes
POST /v1/companies/search/1–100 (25)Also accepts sort.
POST /v1/mining-assets/search/1–100 (25)Also accepts sort.
POST /v1/publications/search/1–50 (20)Ordering via its own order param (newest, oldest, relevance).
POST /v1/people/search/1–25 (10)
GET /v1/mining-assets/{id}/drill-results/1–100 (25)Query parameters rather than a JSON body.

The other dataset sub-resources — production, reserves, economic assessments, the two ownership endpoints, and the commodity registry — take no limit/offset and return every row in one response: per-entity row counts there are bounded, so there is nothing to page. See Dataset sub-resources.

The paged response shape

Every paginated response carries the same four fields alongside results:

{
  "results": [ ... ],
  "count": 1240,
  "truncated": true,
  "limit": 100,
  "offset": 0
}
  • count — total matches across all pages.
  • truncatedtrue while more rows remain (count > offset + len(results)). Advance offset by limit and repeat the request until it comes back false.
  • limit / offset — the window actually used, echoing your request after clamping.

Clamping, not rejection

An out-of-range or unparseable limit/offset is clamped silently, never rejected: limit is clamped into the endpoint's range (junk falls back to the default), offset to ≥ 0. This is uniform across every paginated endpoint — a page window is treated as caller arithmetic, not defective data. Invalid data still fails closed: an unknown asset id on /drill-results/ is a 400 invalid_argument.

Sorting

The company and mining-asset searches accept an optional sort — a column key from the resource's curated vocabulary, prefixed with - for descending:

{
  "filters": [],
  "sort": "-market_cap_in_usd",
  "limit": 100,
  "offset": 0
}

Sortable keys are marked "sortable": true in GET /v1/filters/{resource}/ and in the filter & column reference. A key outside that set is a 400 unsupported_sort_field — validated fail-closed, like filters and columns.

Two properties worth relying on:

  • Ordering is deterministic. Every sort gets an internal primary-key tiebreaker appended, so rows with equal sort values don't shuffle between pages.
  • Always send an explicit sort when you paginate. Without one, rows come back in the endpoint's own declared order — for both company and mining-asset search that is descending gold production, not name — and a result set ordered by a value that moves is not stable across pages while rows are being updated underneath your sweep.

Enumerating the universe

Sending an empty (or omitted) filters list to the company or mining-asset search enumerates — it returns the endpoint's whole searchable population, paged like any other search. That population is already scoped before any filter applies:

EndpointBare-enumeration scopeExcluded
POST /v1/companies/search/Active companies, every industryDeactivated companies
POST /v1/mining-assets/search/Active, verified mining assetsAssets that failed verification (not existing, not unique, or no core data)

Industry is not part of that scope. A bare enumeration returns active companies across every industry; narrow it with an explicit filter, so {"field": "industry", "operator": "has_any", "value": ["mining"]} returns the mining slice and ["steel"] returns steel companies.

Changed: company enumeration previously applied a mining filter whenever a request named no industry, so a bare enumeration returned only mining companies. It no longer does. If your mirror relies on that narrowing, add the explicit industry filter above — otherwise it will start receiving companies from other industries.

A full enumeration is the backbone of an ingestion mirror — it is how you detect entities that have left the universe, which watermark sweeps can never show you. See Incremental sync for that recipe.

Go deeper

  • Incremental sync — using the watermark columns plus periodic enumeration to keep a local mirror current.
  • Filters — the curated vocabulary the sort keys come from.

On this page