You are viewing the documentation of the new API versions. We would love to hear from you. You can write to use at support@crustdata.co for feedback and clarifications.
Use this file to discover all available pages before exploring further.
POST /data_lab/job_listings/Table/
POST /job/search
This page lists every behavioral and contract change between the legacy
job-listings dataset-query endpoint and the current job-search endpoint.
Use it as a side-by-side reference when porting an integration; each
section gives the old shape, the new shape, and the smallest edit that
closes the gap.
Topic
Legacy
Current
Path
POST /data_lab/job_listings/Table/
POST /job/search
Method
POST with a JSON body
POST with a JSON body
Auth
Authorization: Token <key>
Authorization: Bearer <key>
Version
(not required)
x-api-version: 2025-11-01 (required)
Base URL
https://api.crustdata.com
https://api.crustdata.com
Three header / shape changes are required. The path and body
grammar moved to a job-specific endpoint, the authorization scheme
moved from Token <key> to Bearer <key>, and the
x-api-version: 2025-11-01 header is now required on every call.
Calls missing any of these are rejected.
The legacy endpoint was a generic dataset-query API parameterized by
a dataset_id (job_listings) and a view_type (Table). The new
endpoint is a purpose-built job-search API — there is no dataset_id
or view_type in the URL, and the request body no longer carries a
dataset object. For real-time retrieval of currently-open roles
for a single company, use
Live Job Search instead of the
legacy sync_from_source=true flag.
The request body moved from a generic-dataset shape (with dataset,
tickers, functions, groups, sync_from_source, background_task,
offset) to a job-specific shape with cursor pagination and structured
aggregations.
Legacy key
Current key
Notes
dataset
(removed)
The endpoint path identifies the dataset. Drop { "name": "job_listings", "id": "joblisting" } from the body.
filters
filters
Grammar changed — see Filter grammar below. The key is unchanged, but column → field.
sorts
sorts
Same array shape. { column, order }. Field names changed — see Field-name mapping.
count
limit
Removed count as an alias. Use limit exclusively.
limit
limit
Unchanged key. Default 20, max 1000 (up from 100).
offset
cursor
Pagination moved from numeric offset to opaque cursor — see Pagination.
groups
aggregations[].type=group_by
Group-by is now expressed inside aggregations — see Aggregations.
The condition key changed from column to field. The and/or group
shape is unchanged, and operators are unchanged. The list of filterable
fields was narrowed to indexed fields only.
Filtering on any other column returns 400 with
"Unsupported columns in conditions: [...]". Legacy integrations that
relied on filtering by raw firmographic columns (e.g.,
linkedin_industries directly, or last_funding_round_type) should
move those filters to the indexed names above or compose them on
Company Search first.
The legacy endpoint returned a fields[] + rows[][] table where each
column was identified by a flat api_name like title, company_name,
linkedin_industries, or date_added. The current endpoint returns
structured job objects with nested sections (job_details, company,
location, content, metadata) — filter and sort references must use
the new dot-paths.
The legacy response carried a single flat city, location_text,
country, state, and district columns (and several *_geocode
foreign-key columns). The current response groups these under location
with both parsed values and the raw posting string.
The legacy response interleaved flat company columns (company_id,
company_name, company_website_domain, linkedin_industries,
linkedin_headcount, linkedin_followers, crunchbase_*, gartner_*,
glassdoor_*, …) into the same row as the job columns. The current
response nests these under a single company object using the same
section names as Company Enrich.
The legacy endpoint returned every column in the dataset by default. The
new endpoint accepts an optional fields array — request only the
sections you need to keep payloads small.
Valid top-level groups: crustdata_job_id, job_details, company,
location, content, metadata. Use dot-notation for nested fields
(company.headcount, company.basic_info.name).When fields is omitted, all available sections are returned.
Group-by has moved out of the top-level groups key and now lives
inside aggregations. Each aggregation declares its type (count or
group_by) explicitly.
Set limit: 0 on the request when you only want aggregation output
and no job rows. The response’s job_listings array will be empty
and aggregations[] will carry the buckets.
The set of columns you can group by is restricted on the new endpoint:company.basic_info.company_id, company.basic_info.industries,
company.basic_info.primary_domain, company.funding.last_round_type,
company.headcount.range, company.locations.country,
job_details.category, job_details.title, job_details.workplace_type,
location.country.Grouping by any other column returns 400 with
"Unsupported aggregation column: '...'".
The legacy endpoint accepted sync_from_source: true to bypass the
indexed dataset and pull live job listings from the web for a single
company. This flag has been removed from /job/search — the current
endpoint serves the indexed dataset only.For real-time job retrieval, call the dedicated live endpoint instead —
see Live Job Search. It accepts a
single crustdata_company_id and returns up to 100 currently-open job
listings from the web.
The legacy background_task: true flag enqueued an asynchronous bulk
fetch of job listings for up to 10 companies, returning a task handle
the caller could poll. This mode has been removed; build pagination
around cursor-based requests on /job/search instead.
The legacy URL embedded a view_type (Table) and the body required a
dataset object ({ "name": "job_listings", "id": "joblisting" }).
Both have been removed — /job/search is purpose-built for job listings.
The legacy tickers array narrowed results to a set of stock or private
tickers (e.g., "PRIVATE:STRIPE"). This input is not part of
/job/search; filter by company.basic_info.company_id or
company.basic_info.primary_domain instead.
The legacy server-side compressed-response variant has been removed. If
you need a compact payload, request only the fields you need with the
new fields array.
Pagination moved from numeric offset (offset + limit) to opaque
cursors. Each response carries a next_cursor value — pass it back as
cursor on the next request to get the following page.
Cursors encode the full query state (filter, sort, field selection).
If you change any of those between page requests, drop the cursor and
paginate from the beginning. next_cursor is null on the final
page.
The envelope shape changed. The legacy endpoint returned a
{ fields, rows } table where each row was a positional array of
column values. The current endpoint returns a paginated
{ job_listings, next_cursor, total_count, aggregations } envelope
where each entry is a structured Job object.
Replace offset-based pagination with cursor from next_cursor.
Drop count as an alias for limit — use limit exclusively. Raise the default cap if needed: new max is 1000.
Move groups into aggregations[] with type: group_by. Add the required agg: count and optional size.
Wrap legacy aggregations: [{ column, type: count }] as aggregations: [{ type: count }] — drop the column for count.
Set limit: 0 when you only want aggregation output (and no job rows).
Update parsers for the new structured envelope { job_listings, next_cursor, total_count, aggregations } — the legacy { fields, rows } table shape is gone.
Update row parsers: each Job is a nested object with crustdata_job_id, job_details, company, location, content, metadata rather than a positional array.
Replace flat company_*, linkedin_*, crunchbase_* column reads with the new nested company.* paths (see Field-name mapping).
Replace flat city / state / country / location_text reads with location.{city,state,country,raw,district,pincode}.
Replace date_added / date_updated reads with metadata.date_added / metadata.date_updated.
Add a fields array if you only need a subset of sections.
Update error handlers for the new error.type / error.message envelope.
If you relied on /data_lab/job_listings/Table/compressed, request a slimmer payload via fields instead.