Skip to main content

Use case

Search people or companies with simple_filters or filters. Discover valid fields first, inspect top values for one field, then run the paginated search.

API Reference

See the full request/response schema and parameters in the API Reference.

Pricing

See Credits & Pricing Guide for credit costs.

Errors

For error responses (400, 403, 404, 409, 503, etc.), see Handling Errors.

Rate limits

Filter-search-specific API rate limits.
LimitValue
POST /search/query200 requests per minute per organization
POST /search/filter-field-values20 requests per minute per organization

Core concepts

TermDescription
simple_filtersThe primary query input format for search and field-values requests. Supports Mongo-style operators such as $eq, $in, $gte, $match, and $and.
filtersThe DSL backup query format. The API rejects queries that exceed the field and query limits defined by GET /search/filter-capabilities.
exclude_entity_idsExcludes specific people or companies from /search/query results by ID. In people mode it accepts LinkedIn public IDs or profile URLs; in company mode, LinkedIn company IDs, URLs, slugs, or website domains. See Search Exclusions.
exclude_list_idsExcludes members of a reusable saved exclusion list. The list’s entity type must match the search mode. See Search Exclusions.
fieldsUnified field metadata returned by GET /search/filter-capabilities. Use it to discover queryable, sortable, rangeable, and top-value-capable fields.
filter_snippetA ready-to-use exact-match clause in filters format returned alongside each top value. Use it when you need filters.
cursorA pagination token returned as next_cursor. Pass it as the only field in follow-up requests to fetch the next page.

Simple filters

simple_filters is the primary query format for this API. It supports common exact-match, range, logical, and text-search operations with concise JSON syntax.

Top-level shape

{
  "simple_filters": {
    "hq_country_iso2": { "$eq": "US" },
    "employees_count": { "$gte": 100, "$lte": 5000 }
  }
}

Supported operators

The capabilities response exposes supported simple-query operators in simple_query_operators.
OperatorDescription
$eq, $neExact match or exact exclusion.
$gt, $gte, $lt, $lteNumeric or date range comparisons.
$in, $ninMatch or exclude multiple exact values.
$existsMatch documents where a field is present or absent.
$match, $phraseText matching for one field.
$and, $or, $not, $norLogical composition.
$elemMatchMatch nested array elements. See Nested array matching for path and type requirements.
$searchFull-text search across supported fields.
$sortSort results in search requests.
$limitLimit result count in search requests.

Nested array matching ($elemMatch)

$elemMatch queries fields inside nested arrays. Two mistakes account for nearly all failed queries:
  • Relative path — companyData.memberId instead of the full dotted path currentCompanies.companyData.memberId
  • Wrong type — passing a numeric ID as a string ("1234567") when the field’s value_type is long
A relative path or type mismatch inside $elemMatch returns zero results or a misleading 400 — not always a clear error. Check the full dotted path and value_type in GET /search/filter-capabilities before querying.
Find people currently at a specific company by LinkedIn memberId:
{
  "mode": "people",
  "simple_filters": {
    "currentCompanies": {
      "$elemMatch": {
        "currentCompanies.companyData.memberId": 1234567
      }
    }
  }
}
The common wrong form — same request shape, but relative path and string ID:
{
  "mode": "people",
  "simple_filters": {
    "currentCompanies": {
      "$elemMatch": {
        "companyData.memberId": "1234567"
      }
    }
  }
}
Both the relative path (companyData.memberId instead of currentCompanies.companyData.memberId) and the string ID ("1234567" instead of 1234567) cause this query to fail. $elemMatch must be keyed on the field’s nested_path from capabilities — not always the outermost array. currentCompanies.companyData.memberId has nested_path: "currentCompanies", so $elemMatch keys on currentCompanies. currentCompanies.positions.title has nested_path: "currentCompanies.positions", so $elemMatch on currentCompanies cannot reference a positions field.

Excluding results

There are two ways to exclude records:
  • Use simple_filters operators such as $ne, $nin, $not, and $nor to exclude records that match field conditions.
  • Use the top-level exclusion fields — exclude_entity_ids or exclude_list_ids — to suppress specific people or companies by ID. See Search Exclusions for identifier formats, saved lists, and limits.
Operator-based exclusions affect matching, pagination, and result counts. ID-based exclusions are applied after matching, so pages can return fewer rows than page_size. Don’t rely on total_available to count excluded records or size pagination — page until next_cursor is null.
Cursor requests must send only {"cursor": "..."}. You cannot add or change exclusions while paging through an existing cursor. Include exclusions in the first /search/query request.

Query examples

Find US-based companies:
{
  "mode": "company",
  "simple_filters": {
    "hq_country_iso2": { "$eq": "US" }
  }
}
Find US-based companies with at least 4 employees:
{
  "mode": "company",
  "simple_filters": {
    "hq_country_iso2": { "$eq": "US" },
    "employees_count": { "$gte": 4 }
  }
}
Exclude companies in specific industries:
{
  "mode": "company",
  "simple_filters": {
    "industry": { "$nin": ["Staffing", "Recruiting"] }
  }
}
Find US-based companies while excluding public companies:
{
  "mode": "company",
  "simple_filters": {
    "hq_country_iso2": { "$eq": "US" },
    "is_public": { "$ne": true }
  }
}
Exclude records using logical negation:
{
  "mode": "company",
  "simple_filters": {
    "$and": [
      { "hq_country_iso2": { "$eq": "US" } },
      {
        "$not": {
          "categories_and_keywords": { "$match": "staffing" }
        }
      }
    ]
  }
}
Exclude records that match any disallowed condition:
{
  "mode": "company",
  "simple_filters": {
    "$nor": [
      { "industry": { "$eq": "Staffing" } },
      { "categories_and_keywords": { "$match": "recruiting" } }
    ]
  }
}
Find US-based companies with at least 4 employees where a post mentions YC X25:
{
  "mode": "company",
  "simple_filters": {
    "$and": [
      { "hq_country_iso2": { "$eq": "US" } },
      { "employees_count": { "$gte": 4 } },
      { "company_updates.description": { "$match": "(YC X25)" } }
    ]
  }
}
Find US-based companies sorted by employee count descending, capped to 8 total results:
{
  "mode": "company",
  "simple_filters": {
    "hq_country_iso2": { "$eq": "US" },
    "$sort": [{ "employees_count": "desc" }],
    "$limit": 8
  }
}
Find Canadian companies that have raised any amount and mention technology in categories or keywords:
{
  "mode": "company",
  "simple_filters": {
    "$and": [
      { "hq_country_iso2": { "$eq": "CA" } },
      { "last_funding_round_amount_raised": { "$gt": 0 } },
      { "categories_and_keywords": { "$match": "technology" } }
    ]
  }
}
Full-text search across specific fields:
{
  "mode": "company",
  "simple_filters": {
    "$search": {
      "query": "cloud security",
      "fields": ["description", "categories_and_keywords"]
    }
  }
}
Find people whose headline matches “engineer”:
{
  "mode": "people",
  "simple_filters": {
    "headline": { "$match": "engineer" }
  }
}
Find people by current job title:
{
  "mode": "people",
  "simple_filters": {
    "currentCompanies.positions.title": { "$match": "engineering manager" }
  }
}
Fields with a doubly nested path accept $elemMatch on the inner nested path:
{
  "mode": "people",
  "simple_filters": {
    "currentCompanies.positions": {
      "$elemMatch": {
        "currentCompanies.positions.title": { "$match": "engineering manager" }
      }
    }
  }
}
Find people currently at a specific company by LinkedIn memberId — see the full example and path/type requirements in Nested array matching ($elemMatch).

DSL filters

filters accepts a constrained DSL subset for cases where simple_filters is not expressive enough. For DSL syntax and clause behavior, see the OpenSearch Query DSL docs.

Top-level shape

{
  "filters": {
    "query": { ... },
    "sort": [ ... ],
    "size": 100
  }
}

Supported query clauses

ClauseDescription
boolCombine conditions with must, filter, should, and must_not.
termExact-match query for a single value.
termsExact-match query for multiple values.
rangeNumeric or date range with gt, gte, lt, lte.
existsMatch documents where a field is present.
matchFull-text match query.
match_phrasePhrase query.
multi_matchSearch the same value across multiple fields.
nestedQuery nested arrays and nested objects.
match_allMatch all records in the selected mode.

Query examples

Exact match:
{
  "term": {
    "website_domain": "stripe.com"
  }
}
Range filter:
{
  "range": {
    "employees_count": {
      "gte": 100,
      "lte": 5000
    }
  }
}
Multi-field full-text search:
{
  "multi_match": {
    "query": "cloud security",
    "fields": [
      "description",
      "categories_and_keywords"
    ],
    "type": "best_fields",
    "operator": "and"
  }
}
Nested query:
{
  "nested": {
    "path": "funding_rounds",
    "query": {
      "match_phrase": {
        "funding_rounds.name": "Series B"
      }
    }
  }
}
Exclude with must_not:
{
  "bool": {
    "must": [
      { "term": { "hq_country_iso2": "US" } }
    ],
    "must_not": [
      { "term": { "industry": "Staffing" } }
    ]
  }
}

Filter capabilities

GET https://api.sixtyfour.ai/search/filter-capabilities
Returns all available fields for filter search — the complete list of fields you can query, sort, range, or aggregate against, plus the supported simple_filters operators and DSL limits.
Call this first to discover what is filterable before constructing any simple_filters or filters request. The response is the source of truth: a field that is not in fields cannot be queried.

Query parameters

ParameterTypeDescription
modestringpeople or company. Defaults to company.
refreshbooleanForce a mapping refresh instead of returning cached capabilities. Defaults to false.

Example request

curl -X GET "https://api.sixtyfour.ai/search/filter-capabilities?mode=company" \
  -H "x-api-key: YOUR_API_KEY"

Response shape

FieldTypeDescription
fieldsarrayEvery queryable field in the selected mode. See Field entry.
nested_pathsstring[]Top-level paths that map to nested arrays or objects. Fields underneath these paths require a nested clause when using filters.
simple_query_operatorsstring[]Operators allowed in simple_filters ($eq, $in, $gte, $match, etc.).
limitsobjectHard limits applied to filters queries. See Limits.
cache_ttl_secondsintegerSeconds the response is cached server-side. Pass refresh=true to bypass.
generated_at_epoch_msintegerWhen the cached payload was built.
mapping_hashstringHash of the underlying index mapping. Changes when fields are added or removed.

Limits

LimitDescription
max_query_depthMaximum nesting depth of filters.query.
max_clause_countMaximum total clauses across a filters query.
max_terms_per_clauseMaximum values in a single terms or $in clause.
max_sort_clausesMaximum sort fields.
max_string_lengthMaximum length of any string value in a query.

Field entry

Each item in fields describes one queryable field.
PropertyTypeDescription
fieldstringThe field path to use in simple_filters and filters.
field_typestringUnderlying index type (keyword, text, long, double, integer, date, search_as_you_type).
value_typestringThe value type clients should send. Matches field_type except for text fields, which expose keyword for filtering.
nested_pathstring | nullSet when the field lives inside a nested array. Use a nested clause with path set to this value for DSL queries.
queryablebooleanWhether the field is valid in simple_filters and filters.
sortablebooleanWhether the field can be used in $sort or DSL sort.
rangeablebooleanWhether the field accepts $gt, $gte, $lt, $lte, or DSL range.
sort_fieldstring | nullAlternate path used when sorting. Text fields sort on the .keyword subfield.
aggregation_fieldstring | nullPath used for top-value aggregation in POST /search/filter-field-values.
supports_top_valuesbooleanWhether the field can be passed to POST /search/filter-field-values.
supports_exact_filter_snippetbooleanWhether a filter_snippet is returned alongside top values for this field.
related_fieldsstring[]Other fields that pair with this one (e.g. range pairs, currency + value).
preferred_for_exact_matchbooleanWhen multiple fields describe the same concept, the preferred field for exact-match queries.

Example response

Trimmed to two representative fields — a top-level keyword and a nested numeric.
{
  "fields": [
    {
      "field": "website",
      "field_type": "keyword",
      "value_type": "keyword",
      "nested_path": null,
      "queryable": true,
      "sortable": true,
      "rangeable": false,
      "sort_field": null,
      "aggregation_field": "website",
      "supports_top_values": true,
      "supports_exact_filter_snippet": true,
      "related_fields": [],
      "preferred_for_exact_match": false
    },
    {
      "field": "stock_information.marketcap",
      "field_type": "double",
      "value_type": "double",
      "nested_path": "stock_information",
      "queryable": true,
      "sortable": true,
      "rangeable": true,
      "sort_field": null,
      "aggregation_field": "stock_information.marketcap",
      "supports_top_values": true,
      "supports_exact_filter_snippet": true,
      "related_fields": [],
      "preferred_for_exact_match": false
    }
  ],
  "nested_paths": [
    "funding_rounds",
    "stock_information",
    "technologies_used",
    "visits_breakdown_by_country"
  ],
  "simple_query_operators": [
    "$eq", "$ne", "$gt", "$gte", "$lt", "$lte",
    "$in", "$nin", "$exists", "$match", "$phrase",
    "$and", "$or", "$not", "$nor", "$elemMatch",
    "$search", "$sort", "$limit"
  ],
  "limits": {
    "max_query_depth": 12,
    "max_clause_count": 200,
    "max_terms_per_clause": 25,
    "max_sort_clauses": 2,
    "max_string_length": 200
  },
  "cache_ttl_seconds": 600,
  "generated_at_epoch_ms": 1779726915580,
  "mapping_hash": "3c507eb2e597605197fac2beb483fbbf619f628ce45b2c2c446825289347a24a0"
}

Common lookups

Filter the fields array client-side to find what is available for a given operation.
GoalProperty
Fields usable in simple_filters or filtersqueryable: true
Fields usable in $sort or DSL sortsortable: true
Fields that accept range operatorsrangeable: true
Fields that can be passed to /search/filter-field-valuessupports_top_values: true
Fields that require a nested clause in DSLnested_path is non-null
Fields that return filter_snippet for reuse in filterssupports_exact_filter_snippet: true

Find specific fields

To confirm that a field exists and see what operators it accepts, filter the fields array by name. The examples below check hq_country_iso2 and employees_count — the same fields used in the simple_filters examples earlier on this page.
curl -s "https://api.sixtyfour.ai/search/filter-capabilities?mode=company" \
  -H "x-api-key: YOUR_API_KEY" \
  | jq '.fields[] | select(.field == "hq_country_iso2" or .field == "employees_count")'
If a field is missing from fields, it cannot be queried. If queryable is false, the field is exposed but reserved for sort or aggregation only. If nested_path is non-null, wrap the clause in a nested query when using filters. To search by partial name (e.g. every revenue-related field):
curl -s "https://api.sixtyfour.ai/search/filter-capabilities?mode=company" \
  -H "x-api-key: YOUR_API_KEY" \
  | jq '.fields[] | select(.field | test("revenue")) | .field'
Capabilities are cached for cache_ttl_seconds (typically 600s). Pass refresh=true only when verifying schema changes — every refresh rebuilds the mapping and is slower.

Field values

POST https://api.sixtyfour.ai/search/filter-field-values
Returns top values for one field, ranked by descending scoped document count. There is no batch variant.

Scoped query

  • Omit both simple_filters and filters for global scope.
  • Send either simple_filters or filters for scoped discovery.
  • filters.sort, filters.size, and mixed filters plus simple_filters requests are not allowed on this endpoint.
  • simple_filters.$sort and simple_filters.$limit are not supported on this endpoint.
{
  "simple_filters": {
    "hq_country_iso2": { "$eq": "US" }
  }
}
Use filter-field-values with a high top_k to enumerate valid values for any enum-like field before filtering. This prevents querying with values that return zero results.
Discover all available industries:
curl -s -X POST "https://api.sixtyfour.ai/search/filter-field-values" \
  -H "x-api-key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"mode": "company", "field": "industry", "top_k": 100}'
The same pattern works for any enum-like field: ownership_status, hq_country_iso2, funding_stage, and so on. Check supports_top_values: true in the capabilities response to confirm the field supports this endpoint.

Example request

Global:
curl -X POST "https://api.sixtyfour.ai/search/filter-field-values" \
  -H "x-api-key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"mode": "company", "field": "hq_country_iso2", "top_k": 4}'
Scoped:
{
  "mode": "company",
  "field": "industry",
  "top_k": 4,
  "simple_filters": {
    "hq_country_iso2": { "$eq": "US" },
    "employees_count": { "$gte": 200, "$lte": 5000 },
    "ownership_status": { "$eq": "private" }
  }
}

Nested fields

For nested fields such as funding_rounds.name, counts are document counts and each filter_snippet is wrapped in a nested clause so it can be reused directly in DSL flows.

Search query

POST https://api.sixtyfour.ai/search/query
Runs a paginated search. Fresh searches accept simple_filters, filters, parsed_query, or a search_id to re-run a previous search.

Request flow

  1. First request: send exactly one of simple_filters, filters, parsed_query, or search_id, plus optional page_size, max_results, and exclusions (exclude_entity_ids, exclude_list_ids).
  2. Next page request: send only {"cursor":"..."}.
  3. Requests that mix cursor with query or pagination fields return 400.

Effective result cap

  • page_size controls rows per page. Range 1..100. Default 10.
  • max_results controls the total row cap across all pages. Range 1..5000.
  • simple_filters.$limit and filters.size are optional query-level caps.
  • When both max_results and a query-level cap are set, the smaller value applies.
  • When no total cap is set, the backend default applies.

Example request

Fresh search:
curl -X POST "https://api.sixtyfour.ai/search/query" \
  -H "x-api-key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "mode": "company",
    "simple_filters": {
      "hq_country_iso2": { "$eq": "US" },
      "employees_count": { "$gte": 100, "$lte": 5000 }
    }
  }'
Exclude specific people with exclude_entity_ids:
{
  "mode": "people",
  "parsed_query": {
    "jobTitleExperience": {
      "titles": ["VP Engineering", "Head of Engineering"],
      "searchBoth": false
    }
  },
  "exclude_entity_ids": ["john-doe-123", "https://linkedin.com/in/jane-smith-456"]
}
Use exclusions when re-running or refining a search and you want to avoid returning records the user has already seen. People searches also accept exclude_public_ids for backward compatibility. For full details — company identifiers, saved lists, and limits — see Search Exclusions. Re-run a previous search:
{
  "search_id": "e3b0c442-98fc-1c14-9afb-f4c8996fb924"
}
Next page:
{
  "cursor": "eyJpZCI6I..."
}
raw_source returns the document directly. It does not use grouped objects such as identity, profile, or location.

Export search results

Export results from any search as a CSV. See Export Search Results for the full endpoint reference.

Example usage

The following examples walk through the full recommended flow: discover valid fields, inspect top values for one field, then paginate through results.
API_KEY="YOUR_API_KEY"
BASE_URL="https://api.sixtyfour.ai"

# 1. Get filter capabilities to discover valid fields
curl -s "$BASE_URL/search/filter-capabilities" \
  -H "x-api-key: $API_KEY" \
  | jq '[.fields[] | select(.queryable) | .field] | .[0:5]'

# 2. Inspect top values for a field to build a simple filter
TOP_COUNTRY=$(curl -s -X POST "$BASE_URL/search/filter-field-values" \
  -H "x-api-key: $API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"mode": "company", "field": "hq_country_iso2", "top_k": 4}' \
  | jq -r '.values[0].value')
echo "Top country: $TOP_COUNTRY"

# 3. Run the paginated filter search, following cursors until has_more is false
CURSOR=""
while true; do
  if [ -z "$CURSOR" ]; then
    PAYLOAD=$(jq -nc --arg c "$TOP_COUNTRY" \
      '{mode:"company", simple_filters:{hq_country_iso2:{"$eq":$c}, employees_count:{"$gte":100}}}')
  else
    PAYLOAD=$(jq -nc --arg cur "$CURSOR" '{cursor:$cur}')
  fi

  RESP=$(curl -s -X POST "$BASE_URL/search/query" \
    -H "x-api-key: $API_KEY" \
    -H "Content-Type: application/json" \
    -d "$PAYLOAD")

  echo "$RESP" | jq -r '"Page \(.page_number) — \(.page_count) rows"'

  HAS_MORE=$(echo "$RESP" | jq -r '.has_more')
  [ "$HAS_MORE" != "true" ] && break
  CURSOR=$(echo "$RESP" | jq -r '.next_cursor')
done