How to paginate, sort, select fields, and aggregate results in Search Jobs. For filter grammar and example queries, see Filters & recipes. For the full field catalog and errors, see Reference.Documentation Index
Fetch the complete documentation index at: https://docs.crustdata.com/llms.txt
Use this file to discover all available pages before exploring further.
Replace
YOUR_API_KEY in each example with your actual API key. All
requests require the x-api-version: 2025-11-01 header.Sorting
sorts is an ordered array. Each item has a column and order ("asc"
or "desc"). Sorts apply in array order — the first sort is the primary
key, the second breaks ties, and so on.
Sortable fields
The following indexed fields are verified sortable:metadata.date_addedmetadata.date_updatedcompany.headcount.totalcompany.followers.countcompany.revenue.estimated.lower_bound_usdcompany.revenue.estimated.upper_bound_usdcompany.funding.total_investment_usdcompany.funding.valuation_usdcompany.funding.last_fundraise_datecompany.funding.num_funding_rounds
- Newest postings first —
{ "column": "metadata.date_added", "order": "desc" } - Biggest companies first —
{ "column": "company.headcount.total", "order": "desc" } - Most followed companies first —
{ "column": "company.followers.count", "order": "desc" } - Highest-funded companies first —
{ "column": "company.funding.total_investment_usd", "order": "desc" }
Pagination
Pagination is cursor-based. Each response returns anext_cursor (or
null when you reach the end). To fetch the next page, resend the original
request body with cursor set to the previous next_cursor.
Walk forward
Take
next_cursor from the response and pass it back as cursor
in the next request. Keep filters, sorts, and fields
identical — if you change them, the cursor becomes meaningless.Consistency between pages
Current platform behavior — best-effort, not strict snapshot. A
cursor is consistent with respect to the filter, sort, and field
selection you sent on the first page, so the same query will keep
paging forward over a coherent result stream. However, because the
underlying indexed dataset is continuously updated, new jobs indexed
between page requests can cause minor drift in
total_count and in the
exact position of individual rows. Treat pagination as best-effort,
not a strict snapshot.For bulk exports where every row matters:- Constrain your filter to a bounded date window (for example
metadata.date_added >= 2025-01-01AND< 2025-07-01) so newly indexed jobs outside the window do not affect the walk, and - Re-run the full walk periodically and diff against the prior
snapshot using
crustdata_job_idas the dedupe key.
Dataset freshness and lifecycle
What the indexed Jobs dataset represents. The Search Jobs dataset
is a rolling index of job listings discovered from the web, refreshed
on an ongoing basis. Each row has:
metadata.date_added— when Crustdata first saw the listing.metadata.date_updated— most recent refresh.
metadata.date_added or metadata.date_updated window (for
example, within the last 30 days) and pair it with the hiring
company’s firmographics. For alerting or repeated exports, keep your
date windows bounded and dedupe rows with crustdata_job_id.Date filter semantics
Dates and timezones. When you pass a date-only value like
"2025-01-01", the backend interprets it as 2025-01-01T00:00:00 in
UTC. Ranges using => are inclusive of the boundary and < is
exclusive, so "metadata.date_added" >= "2025-01-01" AND
< "2025-07-01" covers every listing indexed between Jan 1 (inclusive)
and Jul 1 (exclusive) in UTC. Pass full timestamps like
"2025-01-01T08:00:00" when you need finer precision.Fetch page 2
Field selection
Usefields to return only the dot-paths you need. The top-level groups
are crustdata_job_id, job_details, company, location, content,
metadata. You can request:
- A whole group —
"company"returns everycompany.*sub-object. - A sub-object —
"company.basic_info"returns only the basic info block. - A single field —
"company.basic_info.name"returns just the name.
Aggregations
Aggregations let you roll up results without returning individual job rows. Setlimit: 0 when you only want aggregation output. Two types are
supported:
count— returns the total number of jobs matchingfilters.group_by— buckets the results bycolumnand returns per-bucket counts.
AggregationRequest schema
| Field | Type | Required | Description |
|---|---|---|---|
type | string (enum) | Yes | "count" for a simple total, "group_by" to bucket by column. |
column | string | Required for group_by | Dot-path to group by. Must be in the Groupable fields allowlist. |
agg | string (enum) | Required for group_by | Sub-aggregation inside each bucket. Currently only "count" is supported. |
size | integer | No (default 100) | Maximum number of buckets to return. Min 1, max 1000. |
AggregationResponseItem echoes type and column, then carries:
value(integer) — populated forcountaggregations. The total match count.buckets(array) — populated forgroup_byaggregations. Each bucket has akey,count, and ametadataobject whose keys depend on the grouped column. See Aggregation bucket metadata.
aggregations[] in the same order you sent them.
Count all Engineering jobs
Top companies indexing “Software Engineer” listings (bounded window)
Groupable fields
group_by.column is restricted to the following indexed fields:
company.basic_info.company_idcompany.basic_info.industriescompany.basic_info.primary_domaincompany.funding.last_round_typecompany.headcount.rangecompany.locations.countryjob_details.categoryjob_details.titlejob_details.workplace_typelocation.country
400 with Unsupported aggregation column: '...'. Supported: ....
Next steps
- Filters & recipes — filter grammar, operators, and example queries.
- Reference — full field catalog, id map, bucket metadata, and errors.
- Search Jobs — back to the main Search page.

