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.
| Operator | Description |
|---|
$eq, $ne | Exact match or exact exclusion. |
$gt, $gte, $lt, $lte | Numeric or date range comparisons. |
$in, $nin | Match or exclude multiple exact values. |
$exists | Match documents where a field is present or absent. |
$match, $phrase | Text matching for one field. |
$and, $or, $not, $nor | Logical composition. |
$elemMatch | Match nested array elements. |
$search | Full-text search across supported fields. |
$sort | Sort results in search requests. |
$limit | Limit 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
| Term | Description |
|---|
| simple_filters | The primary query input format for search and field-values requests. It supports Mongo-style operators such as $eq, $in, $gte, $match, and $and. |
| DSL filters | The backup query format accepted through filters. The API rejects queries that exceed the field and query limits defined by GET /search/filter-capabilities. |
| fields | Unified field metadata returned by GET /search/filter-capabilities. Use it to discover queryable, sortable, rangeable, and top-value-capable fields. |
| filter_snippet | A ready-to-use exact-match clause in filters format returned alongside each top value. Use it when you need filters. |
| cursor | A pagination token returned as next_cursor. Pass it as the only field in follow-up requests to fetch the next page. |
| Name | Type | Required | Description |
|---|
x-api-key | string | Yes | Your Sixtyfour API key. |
Content-Type | string | For POST requests | Must be application/json. |
Rate Limits
Filter-search-specific API rate limits.
| Limit | Value |
|---|
POST /search/query | 200 requests per minute per organization |
POST /search/filter-field-values | 20 requests per minute per organization |
Recommended Flow
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
}
}
| Key | Type | Description |
|---|
query | object | Required for fresh searches. Must be a non-empty DSL query object. |
sort | array | Optional. Sort clauses for the first request. |
size | integer | Optional. Additional size hint that can drive the effective cap when max_results is omitted. |
Supported Query Clauses
| Clause | Description |
|---|
bool | Combine conditions with must, filter, should, and must_not. |
term | Exact-match query for a single value. |
terms | Exact-match query for multiple values. |
range | Numeric or date range with gt, gte, lt, lte. |
exists | Match documents where a field is present. |
match | Full-text match query. |
match_phrase | Phrase query. |
multi_match | Search the same value across multiple fields. |
nested | Query nested arrays and nested objects. |
match_all | Match 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
| Parameter | Type | Required | Description |
|---|
mode | string | No | "people" or "company". Default "company". |
refresh | boolean | No | Force 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
| Field | Type | Description |
|---|
mode | string | The mode used for this request. |
index_name | string | Public dataset identifier for direct-filter queries for the selected mode. |
fields | array | Unified field metadata for querying, sorting, ranges, and top-value discovery. See fields entry below. |
nested_paths | array of string | Top-level nested paths allowed in DSL nested.path clauses. |
simple_query_operators | array of string | Mongo-style operators accepted in simple_filters. |
limits | object | Guardrail limits for DSL queries. See limits entry below. |
cache_ttl_seconds | integer | Server cache TTL for mapping-derived capabilities. |
generated_at_epoch_ms | integer | Epoch timestamp (ms) when these capabilities were derived. |
mapping_hash | string or null | Hash of the mapping metadata used to derive this capability snapshot. |
fields entry
| Field | Type | Description |
|---|
field | string | Canonical field name to use in API requests. |
field_type | string | Mapping-derived field type. |
queryable | boolean | Whether the field is allowed in query clauses. |
sortable | boolean | Whether the field is allowed in sort clauses. |
rangeable | boolean | Whether the field supports range operators. |
supports_top_values | boolean | Whether POST /search/filter-field-values supports this field. |
sort_field | string or null | Underlying sort field used by the backend when the canonical field sorts through a proxy field. |
aggregation_field | string or null | Underlying field used for top-values aggregation. |
related_fields | array of string | Related canonical fields derived from the same source mapping. |
preferred_for_exact_match | boolean | Whether this field is the preferred exact-match field for its mapping family. |
nested_path | string or null | Nested path for nested fields. |
supports_exact_filter_snippet | boolean | Whether the response can include deterministic exact-match snippets. |
limits entry
| Field | Type | Description |
|---|
max_query_depth | integer | Maximum recursive query depth allowed by the validator. |
max_clause_count | integer | Maximum total query clauses allowed across the full query tree. |
max_terms_per_clause | integer | Maximum values allowed in terms or bool clause lists. |
max_sort_clauses | integer | Maximum number of sort clauses allowed in filters.sort. |
max_string_length | integer | Maximum 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
| Field | Type | Required | Description |
|---|
mode | string | No | "people" or "company". Default "company". |
field | string | Yes | Field to inspect. The field must exist in fields and support top values. |
top_k | integer | No | Number of values to return. Range 1..100. Default 25. |
simple_filters | object | No | Optional scoped simple query. Mutually exclusive with filters. |
filters | object | No | Optional 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
| Field | Type | Description |
|---|
mode | string | The mode used for this request. |
field | string | Field requested in the request. |
canonical_field | string | Canonical field resolved by the server. |
aggregation_field | string or null | Actual backend field aggregated for this request. |
nested_path | string or null | Nested path for nested fields. |
value_type | string | Mapping-derived value type. |
supports_top_values | boolean | Capability flag for this field. |
supports_exact_filter_snippet | boolean | Whether exact snippet generation is available. |
related_fields | array of string | Related canonical fields derived from the same source mapping. |
preferred_for_exact_match | boolean | Whether this field is the preferred exact-match field for its mapping family. |
total_scoped_documents | integer | Number of documents in the active scope. |
request_duration_ms | integer | Server processing time in milliseconds. |
values | array | Top 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
| Field | Type | Description |
|---|
value | any or null | Candidate value. |
count | integer | Document count for this value inside the active scope. |
percent_of_scope | number | count / total_scoped_documents, rounded to 6 decimals. |
filter_snippet | object or null | Ready-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
| HTTP | code | Meaning |
|---|
400 | unsupported_mode | mode is not people or company. |
400 | invalid_scoped_filters | Scoped body is invalid. This includes invalid simple_filters, missing filters.query, unsupported keys, or sending both filters and simple_filters. |
400 | unsupported_field | Field is not supported for value discovery. |
400 | top_values_not_supported | Field exists but does not support top-values aggregation. |
400 | invalid_request | Generic request validation failure. |
504 | opensearch_timeout | Aggregation timed out. Retry with narrower scope or smaller top_k. |
500 | aggregation_failed | Unexpected 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
| Field | Type | Required | Description |
|---|
mode | string | No | "people" or "company". Default "company". Inferred from DB when using search_id. |
simple_filters | object | One of* | Primary query format. Mutually exclusive with other query sources. |
filters | object | One of* | DSL format. Must include a non-empty query object. Optional sort, optional size. |
parsed_query | object | One of* | LLM-generated query object from a deep search (advanced). |
search_id | string | One of* | Re-run a previous search by ID. Mode and query are loaded from the database. |
max_results | integer | No | Total cap across pages. Range 1..5000. Default 1000. |
page_size | integer | No | Page size. Range 1..100. Default 10. |
cursor | string | No | Cursor 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
- First request: send exactly one of
simple_filters, filters, parsed_query, or search_id, plus optional page_size and max_results.
- Next page request: send only
{"cursor":"..."}.
- 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
}
}
]
}
| Field | Type | Description |
|---|
search_id | string or null | Identifier for this search. Use with /search/export to export or re-run later. |
next_cursor | string or null | Cursor for the next page. null when there are no more pages. |
cursor_expires_in_seconds | integer | Seconds until the current cursor expires. |
request_duration_ms | integer | Server-side request duration in milliseconds. |
has_more | boolean | Whether another page is available. |
page_size | integer | Requested page size. |
page_count | integer | Number of rows returned in the current page. |
page_number | integer | Current page number, starting at 1. |
total_pages | integer or null | Final total page count once pagination is exhausted. Omitted while has_more is true. |
max_pages | integer | Maximum page count available under the effective cap for this search. |
remaining_results | integer | Number of rows still available under the effective cap after the current page. |
total_results | integer | Cumulative rows returned so far across the cursor flow. This is not a global match count. |
results | array | Rows for the current page. |
Result Row
| Field | Type | Description |
|---|
raw_document_id | string | Stable identifier for the returned document. |
raw_source | object | Source 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
| Status | Description |
|---|
400 | Invalid or expired cursor, invalid filters, mixed query sources, unsupported mode, invalid page_size, or invalid max_results. |
404 | search_id not found or cursor belongs to another organization. |
409 | Cursor is already being processed. Retry after the in-flight request finishes. |
503 | Search 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)}")