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.
This API is also available via MCP. The same MCP server supports both people and company search. See Filter Search MCP to execute filter searches from Claude Code or another MCP client.

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.
$searchFull-text search across supported fields.
$sortSort results in search requests.
$limitLimit result count in search requests.

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 }
  }
}
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"]
    }
  }
}

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.

Core Concepts

TermDescription
simple_filtersThe primary query input format for search and field-values requests. It supports Mongo-style operators such as $eq, $in, $gte, $match, and $and.
DSL filtersThe backup query format accepted through filters. The API rejects queries that exceed the field and query limits defined by GET /search/filter-capabilities.
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.

Headers

NameTypeRequiredDescription
x-api-keystringYesYour Sixtyfour API key.
Content-TypestringFor POST requestsMust be application/json.

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

Filters

The filters object accepts the DSL query format for records in the selected mode. Use the capabilities endpoint to determine which fields and nested paths are valid before building queries:
GET https://api.sixtyfour.ai/search/filter-capabilities

Top-Level Shape

{
  "filters": {
    "query": { ... },
    "sort": [ ... ],
    "size": 100
  }
}
KeyTypeDescription
queryobjectRequired for fresh searches. Must be a non-empty DSL query object.
sortarrayOptional. Sort clauses for the first request.
sizeintegerOptional. Additional size hint that can drive the effective cap when max_results is omitted.

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"
      }
    }
  }
}

Filter Capabilities

GET https://api.sixtyfour.ai/search/filter-capabilities
Returns the live field contract for filter search in the selected mode, including the unified fields list, supported simple-query operators, and DSL limits.

Query Parameters

ParameterTypeRequiredDescription
modestringNo"people" or "company". Default "company".
refreshbooleanNoForce a mapping refresh instead of using cached capabilities. Default false.

Example Request

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

Response

FieldTypeDescription
modestringThe mode used for this request.
index_namestringPublic dataset identifier for direct-filter queries for the selected mode.
fieldsarrayUnified field metadata for querying, sorting, ranges, and top-value discovery. See fields entry below.
nested_pathsarray of stringTop-level nested paths allowed in DSL nested.path clauses.
simple_query_operatorsarray of stringMongo-style operators accepted in simple_filters.
limitsobjectGuardrail limits for DSL queries. See limits entry below.
cache_ttl_secondsintegerServer cache TTL for mapping-derived capabilities.
generated_at_epoch_msintegerEpoch timestamp (ms) when these capabilities were derived.
mapping_hashstring or nullHash of the mapping metadata used to derive this capability snapshot.

fields entry

FieldTypeDescription
fieldstringCanonical field name to use in API requests.
field_typestringMapping-derived field type.
queryablebooleanWhether the field is allowed in query clauses.
sortablebooleanWhether the field is allowed in sort clauses.
rangeablebooleanWhether the field supports range operators.
supports_top_valuesbooleanWhether POST /search/filter-field-values supports this field.
sort_fieldstring or nullUnderlying sort field used by the backend when the canonical field sorts through a proxy field.
aggregation_fieldstring or nullUnderlying field used for top-values aggregation.
related_fieldsarray of stringRelated canonical fields derived from the same source mapping.
preferred_for_exact_matchbooleanWhether this field is the preferred exact-match field for its mapping family.
nested_pathstring or nullNested path for nested fields.
supports_exact_filter_snippetbooleanWhether the response can include deterministic exact-match snippets.

limits entry

FieldTypeDescription
max_query_depthintegerMaximum recursive query depth allowed by the validator.
max_clause_countintegerMaximum total query clauses allowed across the full query tree.
max_terms_per_clauseintegerMaximum values allowed in terms or bool clause lists.
max_sort_clausesintegerMaximum number of sort clauses allowed in filters.sort.
max_string_lengthintegerMaximum string length allowed in query values.

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.

Request Body

FieldTypeRequiredDescription
modestringNo"people" or "company". Default "company".
fieldstringYesField to inspect. The field must exist in fields and support top values.
top_kintegerNoNumber of values to return. Range 1..100. Default 25.
simple_filtersobjectNoOptional scoped simple query. Mutually exclusive with filters.
filtersobjectNoOptional scoped DSL query. Only filters.query is allowed. Mutually exclusive with simple_filters.

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" }
  }
}

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" }
  }
}

Response

{
  "mode": "company",
  "field": "hq_country_iso2",
  "canonical_field": "hq_country_iso2",
  "aggregation_field": "hq_country_iso2",
  "nested_path": null,
  "value_type": "keyword",
  "supports_top_values": true,
  "supports_exact_filter_snippet": true,
  "related_fields": [],
  "preferred_for_exact_match": true,
  "total_scoped_documents": 12345,
  "request_duration_ms": 47,
  "values": [
    {
      "value": "US",
      "count": 4200,
      "percent_of_scope": 0.340219,
      "filter_snippet": {
        "term": { "hq_country_iso2": "US" }
      }
    }
  ]
}

Response Fields

FieldTypeDescription
modestringThe mode used for this request.
fieldstringField requested in the request.
canonical_fieldstringCanonical field resolved by the server.
aggregation_fieldstring or nullActual backend field aggregated for this request.
nested_pathstring or nullNested path for nested fields.
value_typestringMapping-derived value type.
supports_top_valuesbooleanCapability flag for this field.
supports_exact_filter_snippetbooleanWhether exact snippet generation is available.
related_fieldsarray of stringRelated canonical fields derived from the same source mapping.
preferred_for_exact_matchbooleanWhether this field is the preferred exact-match field for its mapping family.
total_scoped_documentsintegerNumber of documents in the active scope.
request_duration_msintegerServer processing time in milliseconds.
valuesarrayTop values ranked by descending count in the active scope.
When available, filter_snippet is returned in filters format so it can be reused directly in DSL flows.

values entry

FieldTypeDescription
valueany or nullCandidate value.
countintegerDocument count for this value inside the active scope.
percent_of_scopenumbercount / total_scoped_documents, rounded to 6 decimals.
filter_snippetobject or nullReady-to-use exact filter clause in filters format for this value.

Nested Example

For nested fields such as funding_rounds.name, counts are document counts and snippets are wrapped in nested.
{
  "field": "funding_rounds.name",
  "values": [
    {
      "value": "Series A",
      "count": 120,
      "percent_of_scope": 0.15,
      "filter_snippet": {
        "nested": {
          "path": "funding_rounds",
          "query": {
            "term": { "funding_rounds.name.keyword": "Series A" }
          }
        }
      }
    }
  ]
}

Error Codes

HTTPcodeMeaning
400unsupported_modemode is not people or company.
400invalid_scoped_filtersScoped body is invalid. This includes invalid simple_filters, missing filters.query, unsupported keys, or sending both filters and simple_filters.
400unsupported_fieldField is not supported for value discovery.
400top_values_not_supportedField exists but does not support top-values aggregation.
400invalid_requestGeneric request validation failure.
504opensearch_timeoutAggregation timed out. Retry with narrower scope or smaller top_k.
500aggregation_failedUnexpected aggregation failure.

Search Query

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

Request Body

FieldTypeRequiredDescription
modestringNo"people" or "company". Default "company". Inferred from DB when using search_id.
simple_filtersobjectOne of*Primary query format. Mutually exclusive with other query sources.
filtersobjectOne of*DSL format. Must include a non-empty query object. Optional sort, optional size.
parsed_queryobjectOne of*LLM-generated query object from a deep search (advanced).
search_idstringOne of*Re-run a previous search by ID. Mode and query are loaded from the database.
max_resultsintegerNoTotal cap across pages. Range 1..5000. Default 1000.
page_sizeintegerNoPage size. Range 1..100. Default 10.
cursorstringNoCursor for the next page. When present, send only the cursor — no other fields.
*Provide exactly one query source, or cursor alone for pagination.

Request Flow

  1. First request: send exactly one of simple_filters, filters, parsed_query, or search_id, plus optional page_size and max_results.
  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 }
    }
  }'
Re-run a previous search:
{
  "search_id": "e3b0c442-98fc-1c14-9afb-f4c8996fb924"
}
Next page:
{
  "cursor": "eyJpZCI6I..."
}

Response

{
  "search_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
  "next_cursor": "eyJpZCI6I...",
  "cursor_expires_in_seconds": 1800,
  "request_duration_ms": 142,
  "has_more": true,
  "page_size": 10,
  "page_count": 10,
  "page_number": 1,
  "max_pages": 500,
  "remaining_results": 4990,
  "total_results": 10,
  "results": [
    {
      "raw_document_id": "stripe",
      "raw_source": {
        "company_name": "Stripe",
        "hq_country_iso2": "US",
        "employees_count": 8000
      }
    }
  ]
}
FieldTypeDescription
search_idstring or nullIdentifier for this search. Use with /search/export to export or re-run later.
next_cursorstring or nullCursor for the next page. null when there are no more pages.
cursor_expires_in_secondsintegerSeconds until the current cursor expires.
request_duration_msintegerServer-side request duration in milliseconds.
has_morebooleanWhether another page is available.
page_sizeintegerRequested page size.
page_countintegerNumber of rows returned in the current page.
page_numberintegerCurrent page number, starting at 1.
total_pagesinteger or nullFinal total page count once pagination is exhausted. Omitted while has_more is true.
max_pagesintegerMaximum page count available under the effective cap for this search.
remaining_resultsintegerNumber of rows still available under the effective cap after the current page.
total_resultsintegerCumulative rows returned so far across the cursor flow. This is not a global match count.
resultsarrayRows for the current page.

Result Row

FieldTypeDescription
raw_document_idstringStable identifier for the returned document.
raw_sourceobjectSource payload for the row, excluding hidden internal fields.
raw_source returns the document directly. It does not use grouped objects such as identity, profile, or location.

Error Response

StatusDescription
400Invalid or expired cursor, invalid filters, mixed query sources, unsupported mode, invalid page_size, or invalid max_results.
404search_id not found or cursor belongs to another organization.
409Cursor is already being processed. Retry after the in-flight request finishes.
503Search backend is not configured.

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.
import requests

API_KEY = "YOUR_API_KEY"
BASE_URL = "https://api.sixtyfour.ai"
headers = {"x-api-key": API_KEY, "Content-Type": "application/json"}

# 1. Get filter capabilities to discover valid fields
caps = requests.get(
    f"{BASE_URL}/search/filter-capabilities",
    headers=headers,
).json()
queryable_fields = [f["field"] for f in caps["fields"] if f["queryable"]][:5]
print(f"Available queryable fields: {queryable_fields}")
print(f"Supported simple operators: {caps['simple_query_operators']}")

# 2. Inspect top values for a field to build a simple filter
values_resp = requests.post(
    f"{BASE_URL}/search/filter-field-values",
    headers=headers,
    json={"mode": "company", "field": "hq_country_iso2", "top_k": 4},
).json()

# Use the top returned value in simple_filters
top_country = values_resp["values"][0]["value"]
print(f"Top country: {values_resp['values'][0]['value']}")

# 3. Run the paginated filter search using simple_filters
all_results = []
cursor = None

while True:
    if cursor:
        payload = {"cursor": cursor}
    else:
        payload = {
            "mode": "company",
            "simple_filters": {
                "hq_country_iso2": {"$eq": top_country},
                "employees_count": {"$gte": 100},
            },
        }

    resp = requests.post(
        f"{BASE_URL}/search/query",
        headers=headers,
        json=payload,
    ).json()

    all_results.extend(resp["results"])
    print(f"Page {resp['page_number']}{resp['page_count']} rows")

    if not resp["has_more"]:
        break

    cursor = resp["next_cursor"]

print(f"Total rows fetched: {len(all_results)}")