> ## 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.

# Person Autocomplete

> Discover valid field values for Person Search filters using the autocomplete API.

**Use this when** you need to discover exact indexed values before building
a Person Search query — for filter dropdowns, input validation, dataset
exploration, or guided query builders.

The Person Autocomplete API returns ranked field-value suggestions so you
can feed the result straight into a [Person Search](/person-docs/search/introduction)
filter without guessing at valid values.

<Warning>
  This endpoint returns **field values, not person profiles**. It also has
  **no pagination or cursor** — the `limit` parameter (max `100`) is the
  only way to control result size. For a full list of distinct values you
  need to combine Autocomplete with progressively narrower `filters`
  scopes. To fetch person records, use
  [Person Search](/person-docs/search/introduction) or
  [Person Enrich](/person-docs/enrichment/introduction) instead.
</Warning>

<Tip>
  **Mental model.** The top-level **`field`** is the field whose values
  you want suggested — the autocomplete target. **`filters.field`** is
  different: it's any Person Search filter field you use to narrow the
  population that autocomplete runs over. Autocomplete targets come from a
  fixed allowlist; filter fields come from the broader Person Search
  filter vocabulary.
</Tip>

<Note>
  Replace `YOUR_API_KEY` in each example with your actual API key. All
  requests require the `x-api-version: 2025-11-01` header.
</Note>

### At a glance

| Detail          | Value                                                                                  |
| --------------- | -------------------------------------------------------------------------------------- |
| **Endpoint**    | `POST https://api.crustdata.com/person/search/autocomplete`                            |
| **Auth**        | `Authorization: Bearer YOUR_API_KEY`                                                   |
| **API version** | `x-api-version: 2025-11-01` header (required)                                          |
| **Required**    | `field` (string) · `query` (string, may be empty)                                      |
| **Optional**    | `limit` (integer, 1–100, default 20) · `filters` (single condition or condition group) |
| **Response**    | `{ "suggestions": [ { "value": string } ] }`                                           |
| **Errors**      | `400` invalid request · `401` unauthorized · `500` internal                            |
| **Pricing**     | Free — see [Pricing](/general/pricing#person-apis).                                    |

<Note>
  Default `rate-limit` is 45 requests per minute. Send an email to
  [gtm@crustdata.co](mailto:gtm@crustdata.co) to discuss higher limits if
  needed for your use case.
</Note>

<CardGroup cols={3}>
  <Card title="Examples" icon="list-filter" href="#examples">
    Most-common values, narrow with filters, multi-value, numeric
    comparisons, Autocomplete → Search workflow.
  </Card>

  <Card title="Reference" icon="book" href="#reference">
    Contract, operators, request parameters, autocomplete-enabled
    fields, implementation tips, and errors.
  </Card>
</CardGroup>

***

## When to use Autocomplete vs Search

| You want to…                                           | Use                                                   |
| ------------------------------------------------------ | ----------------------------------------------------- |
| Discover valid filter values for a field               | **Autocomplete** (this page)                          |
| See the distinct values a field takes, ranked by count | **Autocomplete** with an empty `query`                |
| Return actual person profiles matching filters         | [**Person Search**](/person-docs/search/introduction) |
| Build a type-ahead dropdown for a filter UI            | **Autocomplete** with a partial `query`               |
| Build a live multi-field query that returns full rows  | [**Person Search**](/person-docs/search/introduction) |

***

## Quick start: discover job title values

Type-ahead lookup on a single field. Pass the user's partial input as
`query` and cap the dropdown size with `limit`.

<CodeGroup>
  ```bash curl theme={"theme":"vitesse-black"}
  curl --request POST \
    --url https://api.crustdata.com/person/search/autocomplete \
    --header 'authorization: Bearer YOUR_API_KEY' \
    --header 'content-type: application/json' \
    --header 'x-api-version: 2025-11-01' \
    --data '{
      "field": "experience.employment_details.current.title",
      "query": "VP",
      "limit": 5
    }'
  ```

  ```python Python theme={"theme":"vitesse-black"}
  import os
  import requests

  response = requests.post(
      "https://api.crustdata.com/person/search/autocomplete",
      headers={
          "Authorization": f"Bearer {os.environ['CRUSTDATA_API_KEY']}",
          "Content-Type": "application/json",
          "x-api-version": "2025-11-01",
      },
      json={
          "field": "experience.employment_details.current.title",
          "query": "VP",
          "limit": 5,
      },
  )
  response.raise_for_status()
  suggestions = response.json()["suggestions"]
  ```

  ```javascript Node.js theme={"theme":"vitesse-black"}
  const response = await fetch(
      "https://api.crustdata.com/person/search/autocomplete",
      {
          method: "POST",
          headers: {
              Authorization: `Bearer ${process.env.CRUSTDATA_API_KEY}`,
              "Content-Type": "application/json",
              "x-api-version": "2025-11-01",
          },
          body: JSON.stringify({
              field: "experience.employment_details.current.title",
              query: "VP",
              limit: 5,
          }),
      },
  );
  if (!response.ok) throw new Error(`HTTP ${response.status}`);
  const { suggestions } = await response.json();
  ```

  ```json Response theme={"theme":"vitesse-black"}
  {
      "suggestions": [
          { "value": "VP" },
          { "value": "VP of Sales" },
          { "value": "vp" },
          { "value": "VP Sales" },
          { "value": "VP Operations" }
      ]
  }
  ```
</CodeGroup>

Each suggestion includes:

* **`value`** — the exact **indexed value**: the raw string stored against `field` in Crustdata's person index. Use it verbatim as a Person Search filter value — two distinct indexed values (for example `"VP"` and `"vp"`) are different filter keys, and substituting one for the other will return different results.

Suggestions are returned ranked by internal frequency within the
(optionally filtered) population. The ranking signal itself is not returned
in the response.

When no values match the `query` (or no values exist within the `filters`
scope), the response returns an empty array — not a 404:

```json No results theme={"theme":"vitesse-black"}
{
    "suggestions": []
}
```

***

## Examples

Worked recipes you can copy, paste, and adapt. Each example is a full
working request. For operators, request parameters, autocomplete-enabled
fields, implementation tips, and errors, see the [Reference](#reference)
below.

<AccordionGroup>
  <Accordion title="Get the most common values for a field">
    Pass an empty `query` to retrieve the top values for the field by frequency.
    Useful for seeding filter dropdowns or showing popular options.

    <CodeGroup>
      ```bash Request theme={"theme":"vitesse-black"}
      curl --request POST \
        --url https://api.crustdata.com/person/search/autocomplete \
        --header 'authorization: Bearer YOUR_API_KEY' \
        --header 'content-type: application/json' \
        --header 'x-api-version: 2025-11-01' \
        --data '{
          "field": "experience.employment_details.current.title",
          "query": "",
          "limit": 5
        }'
      ```

      ```json Response theme={"theme":"vitesse-black"}
      {
          "suggestions": [
              { "value": "Owner" },
              { "value": "Manager" },
              { "value": "Project Manager" },
              { "value": "Intern" },
              { "value": "Software Engineer" }
          ]
      }
      ```
    </CodeGroup>

    <Note>
      Empty-query autocomplete can occasionally
      return blank string values when a field has many empty indexed records.
      Filter those out in your UI if you do not want a blank option.
    </Note>
  </Accordion>

  <Accordion title="Get every value of a closed-enum field">
    Some fields (for example, `open_to_cards` and `employment_type`) have a
    **fixed, known value space**. An empty `query` returns the full set in
    declaration order — useful for populating a static dropdown or chip group
    without an extra round-trip.

    <Tabs>
      <Tab title="open_to_cards">
        `open_to_cards` is a closed enum of exactly three codes. The alias
        `professional_network.open_to_cards` returns the same suggestions and is
        the spelling used by the `/person/search` filter.

        <CodeGroup>
          ```bash Request theme={"theme":"vitesse-black"}
          curl --request POST \
            --url https://api.crustdata.com/person/search/autocomplete \
            --header 'authorization: Bearer YOUR_API_KEY' \
            --header 'content-type: application/json' \
            --header 'x-api-version: 2025-11-01' \
            --data '{
              "field": "open_to_cards",
              "query": "",
              "limit": 10
            }'
          ```

          ```json Response theme={"theme":"vitesse-black"}
          {
              "suggestions": [
                  { "value": "CAREER_INTEREST" },
                  { "value": "HIRING_MANAGER" },
                  { "value": "VOLUNTEERING" }
              ]
          }
          ```
        </CodeGroup>

        Feed any returned `value` back into a `professional_network.open_to_cards`
        filter on `/person/search` to find people who have surfaced that
        open-to signal on their profile.
      </Tab>

      <Tab title="employment_type">
        `employment_type` returns canonical employment labels by frequency. Use any
        returned `value` as an exact-match filter on the corresponding employment
        field — flat (`experience.employment_details.employment_type`),
        current-only (`experience.employment_details.current.employment_type`), or
        past-only (`experience.employment_details.past.employment_type`).

        <CodeGroup>
          ```bash Request theme={"theme":"vitesse-black"}
          curl --request POST \
            --url https://api.crustdata.com/person/search/autocomplete \
            --header 'authorization: Bearer YOUR_API_KEY' \
            --header 'content-type: application/json' \
            --header 'x-api-version: 2025-11-01' \
            --data '{
              "field": "employment_type",
              "query": "",
              "limit": 10
            }'
          ```

          ```json Response theme={"theme":"vitesse-black"}
          {
              "suggestions": [
                  { "value": "Full-time" },
                  { "value": "Part-time" },
                  { "value": "Internship" }
              ]
          }
          ```
        </CodeGroup>
      </Tab>
    </Tabs>
  </Accordion>

  <Accordion title="Narrow suggestions with filters">
    Scope the autocomplete to a subset of the dataset with the optional
    `filters` field. The suggestions are then computed against the filtered
    population.

    `filters` accepts either a single `AutocompleteFilterCondition` or a nested
    `AutocompleteFilterConditionGroup` combined with `and`/`or` logic.

    <Tabs>
      <Tab title="Single condition">
        Use a single `AutocompleteFilterCondition` to filter on one field — for
        example, top "VP" titles among current Google employees.

        <CodeGroup>
          ```bash Request theme={"theme":"vitesse-black"}
          curl --request POST \
            --url https://api.crustdata.com/person/search/autocomplete \
            --header 'authorization: Bearer YOUR_API_KEY' \
            --header 'content-type: application/json' \
            --header 'x-api-version: 2025-11-01' \
            --data '{
              "field": "experience.employment_details.current.title",
              "query": "VP",
              "limit": 5,
              "filters": {
                "field": "experience.employment_details.current.company_name",
                "type": "=",
                "value": "Google"
              }
            }'
          ```

          ```json Response theme={"theme":"vitesse-black"}
          {
              "suggestions": [
                  { "value": "VP" },
                  { "value": "VP of Engineering" },
                  { "value": "VP Engineering" },
                  { "value": "VP Sales" },
                  { "value": "vp" }
              ]
          }
          ```
        </CodeGroup>
      </Tab>

      <Tab title="Condition group (AND/OR)">
        Use an `AutocompleteFilterConditionGroup` to combine multiple conditions
        with `op: "and"` or `op: "or"` — for example, top titles matching
        `"engineer"` at Google in the United States.

        <CodeGroup>
          ```bash Request theme={"theme":"vitesse-black"}
          curl --request POST \
            --url https://api.crustdata.com/person/search/autocomplete \
            --header 'authorization: Bearer YOUR_API_KEY' \
            --header 'content-type: application/json' \
            --header 'x-api-version: 2025-11-01' \
            --data '{
              "field": "experience.employment_details.current.title",
              "query": "engineer",
              "limit": 5,
              "filters": {
                "op": "and",
                "conditions": [
                  {
                    "field": "experience.employment_details.current.company_name",
                    "type": "=",
                    "value": "Google"
                  },
                  {
                    "field": "basic_profile.location.country",
                    "type": "=",
                    "value": "United States"
                  }
                ]
              }
            }'
          ```

          ```json Response theme={"theme":"vitesse-black"}
          {
              "suggestions": [
                  { "value": "Software Engineer" },
                  { "value": "Senior Software Engineer" },
                  { "value": "Staff Software Engineer" },
                  { "value": "Senior Staff Software Engineer" },
                  { "value": "Software Engineer III" }
              ]
          }
          ```
        </CodeGroup>

        Groups can be nested — pass another `AutocompleteFilterConditionGroup`
        inside `conditions` to express arbitrarily complex boolean expressions.
      </Tab>

      <Tab title="Multi-value (in / not_in)">
        Use `in` or `not_in` to match any value in a list. Pass a JSON **array** for
        `value` — a comma-separated string will return a 400.

        Top engineer titles across the United States, United Kingdom, and Canada:

        <CodeGroup>
          ```bash Request (in) theme={"theme":"vitesse-black"}
          curl --request POST \
            --url https://api.crustdata.com/person/search/autocomplete \
            --header 'authorization: Bearer YOUR_API_KEY' \
            --header 'content-type: application/json' \
            --header 'x-api-version: 2025-11-01' \
            --data '{
              "field": "experience.employment_details.current.title",
              "query": "Engineer",
              "limit": 5,
              "filters": {
                "field": "basic_profile.location.country",
                "type": "in",
                "value": ["United States", "United Kingdom", "Canada"]
              }
            }'
          ```

          ```json Response theme={"theme":"vitesse-black"}
          {
              "suggestions": [
                  { "value": "Software Engineer" },
                  { "value": "Senior Software Engineer" },
                  { "value": "Engineer" },
                  { "value": "Project Engineer" },
                  { "value": "Mechanical Engineer" }
              ]
          }
          ```
        </CodeGroup>

        Top seniority levels **excluding** the United States and United Kingdom:

        <CodeGroup>
          ```bash Request (not_in) theme={"theme":"vitesse-black"}
          curl --request POST \
            --url https://api.crustdata.com/person/search/autocomplete \
            --header 'authorization: Bearer YOUR_API_KEY' \
            --header 'content-type: application/json' \
            --header 'x-api-version: 2025-11-01' \
            --data '{
              "field": "experience.employment_details.current.seniority_level",
              "query": "",
              "limit": 5,
              "filters": {
                "field": "basic_profile.location.country",
                "type": "not_in",
                "value": ["United States", "United Kingdom"]
              }
            }'
          ```

          ```json Response theme={"theme":"vitesse-black"}
          {
              "suggestions": [
                  { "value": "Entry Level" },
                  { "value": "Entry Level Manager" },
                  { "value": "Senior" },
                  { "value": "Director" },
                  { "value": "Owner / Partner" }
              ]
          }
          ```
        </CodeGroup>
      </Tab>

      <Tab title="Numeric comparison">
        Pass numeric values as JSON numbers. Filter `value` accepts string, number,
        integer, or boolean scalars; for `in` and `not_in`, use arrays of strings,
        numbers, or integers that match the underlying field's type.

        <CodeGroup>
          ```bash Request theme={"theme":"vitesse-black"}
          curl --request POST \
            --url https://api.crustdata.com/person/search/autocomplete \
            --header 'authorization: Bearer YOUR_API_KEY' \
            --header 'content-type: application/json' \
            --header 'x-api-version: 2025-11-01' \
            --data '{
              "field": "experience.employment_details.current.title",
              "query": "",
              "limit": 3,
              "filters": {
                "field": "experience.employment_details.current.company_headcount_latest",
                "type": ">",
                "value": 10000
              }
            }'
          ```

          ```json Response theme={"theme":"vitesse-black"}
          {
              "suggestions": [
                  { "value": "Owner" },
                  { "value": "Manager" },
                  { "value": "Project Manager" }
              ]
          }
          ```
        </CodeGroup>
      </Tab>
    </Tabs>
  </Accordion>

  <Accordion title="Full workflow: Autocomplete → Search → Enrich">
    This is the canonical end-to-end Person API workflow. Autocomplete discovers
    the exact title value the Search API expects, Search finds matching people,
    and Enrich fills in the details.

    ### Step 1: Discover valid title values

    <CodeGroup>
      ```bash Request theme={"theme":"vitesse-black"}
      curl --request POST \
        --url https://api.crustdata.com/person/search/autocomplete \
        --header 'authorization: Bearer YOUR_API_KEY' \
        --header 'content-type: application/json' \
        --header 'x-api-version: 2025-11-01' \
        --data '{"field": "experience.employment_details.current.title", "query": "VP Sales", "limit": 3}'
      ```

      ```json Response theme={"theme":"vitesse-black"}
      {
          "suggestions": [
              { "value": "VP Sales" },
              { "value": "VP of Sales" },
              { "value": "VP, Sales" }
          ]
      }
      ```
    </CodeGroup>

    **Extract:** Take `suggestions[0].value` → `"VP Sales"`. Use this exact
    string in your Search filter.

    **If empty:** Try a broader query (for example, `"VP"` instead of
    `"VP Sales"`).

    ### Step 2: Search for matching people

    <CodeGroup>
      ```bash Request theme={"theme":"vitesse-black"}
      curl --request POST \
        --url https://api.crustdata.com/person/search \
        --header 'authorization: Bearer YOUR_API_KEY' \
        --header 'content-type: application/json' \
        --header 'x-api-version: 2025-11-01' \
        --data '{
          "filters": {
            "op": "and",
            "conditions": [
              {"field": "experience.employment_details.current.title", "type": "in", "value": ["VP Sales", "VP of Sales"]},
              {"field": "experience.employment_details.current.company_headcount_range", "type": "in", "value": ["51-200", "201-500"]}
            ]
          },
          "limit": 3,
          "fields": ["basic_profile.name", "experience.employment_details.current.title", "experience.employment_details.current.company_name", "social_handles.professional_network_identifier.profile_url"]
        }'
      ```

      ```json Response theme={"theme":"vitesse-black"}
      {
          "profiles": [
              {
                  "basic_profile": { "name": "Jane Smith" },
                  "experience": {
                      "employment_details": {
                          "current": [{ "title": "VP of Sales", "name": "Acme Corp" }]
                      }
                  },
                  "social_handles": {
                      "professional_network_identifier": {
                          "profile_url": "https://www.linkedin.com/in/janesmith"
                      }
                  }
              }
          ],
          "next_cursor": "H4sIACIdzWkC...",
          "total_count": 15420
      }
      ```
    </CodeGroup>

    **Extract:** Take
    `social_handles.professional_network_identifier.profile_url` →
    `"https://www.linkedin.com/in/janesmith"`. Pass the profile URL to Enrich.

    **If empty:** Broaden filters or verify values with an earlier autocomplete
    call.

    ### Step 3: Enrich the top match

    <CodeGroup>
      ```bash Request theme={"theme":"vitesse-black"}
      curl --request POST \
        --url https://api.crustdata.com/person/enrich \
        --header 'authorization: Bearer YOUR_API_KEY' \
        --header 'content-type: application/json' \
        --header 'x-api-version: 2025-11-01' \
        --data '{"professional_network_profile_urls": ["https://www.linkedin.com/in/janesmith"]}'
      ```
    </CodeGroup>

    **Result:** Full person profile with employment history, education, skills,
    and more. See [Person Enrich](/person-docs/enrichment/introduction) for the full
    response shape.

    See [Person Search](/person-docs/search/introduction) for the full filter grammar.
  </Accordion>
</AccordionGroup>

***

## Reference

Reference material for Person Autocomplete: contract vs current behavior,
supported filter operators, request parameters, autocomplete-enabled fields,
implementation tips for UI builders, and errors.

For walk-through examples, see the [Examples](#examples) above.

### Guaranteed contract vs current behavior

Use this table to separate the parts you can build against with confidence
from the observed behavior that may evolve.

| Topic                               | Kind             | What it means                                                                                                                                 |
| ----------------------------------- | ---------------- | --------------------------------------------------------------------------------------------------------------------------------------------- |
| Endpoint, HTTP method, auth headers | **Contract**     | `POST /person/search/autocomplete`, bearer auth, `x-api-version: 2025-11-01`.                                                                 |
| Request body shape                  | **Contract**     | `field` and `query` required, `limit` and `filters` optional, `filters` uses conditions / condition groups with the documented operators.     |
| Response body shape                 | **Contract**     | `{ "suggestions": [ { "value" } ] }`. Empty results return `{"suggestions": []}` with status `200`.                                           |
| Supported operators                 | **Contract**     | `=`, `!=`, `<`, `=<`, `>`, `=>`, `in`, `not_in`, `contains` — see [Supported operators](#supported-operators).                                |
| `limit` bounds and default          | **Contract**     | Minimum `1`, maximum `100`, default `20`.                                                                                                     |
| Error status codes                  | **Contract**     | `400` (invalid request), `401` (unauthorized), `500` (internal).                                                                              |
| Suggestion ranking                  | Current behavior | Suggestions are ranked by internal frequency within the (optionally filtered) population — the ranking signal is not exposed in the response. |
| Case-insensitive query matching     | Current behavior | `"vp"` and `"VP"` currently return the same suggestions.                                                                                      |
| Multi-token query loose matching    | Current behavior | A multi-word `query` may return values containing only one of the tokens.                                                                     |
| Blank-string suggestions            | Current behavior | Empty-`query` calls can return `""` as the top suggestion when a field has many empty indexed records.                                        |

### Supported operators

The `type` field on every `AutocompleteFilterCondition` accepts the same
operators as Person Search filters.

<Warning>
  The **greater-than-or-equal** operator is `=>` (not `>=`) and
  **less-than-or-equal** is `=<` (not `<=`). This is intentional — do not
  mistype them as the more common `<=` and `>=`.
</Warning>

| Operator   | `value` shape                              | Meaning                                                                    |
| ---------- | ------------------------------------------ | -------------------------------------------------------------------------- |
| `=`        | string, number, integer, or boolean        | Exact match — the field value equals `value`.                              |
| `!=`       | string, number, integer, or boolean        | Not equal — the field value differs from `value`.                          |
| `<`        | number or ISO date string                  | Less than — numeric or date comparison.                                    |
| `=<`       | number or ISO date string                  | Less than or equal — numeric or date comparison.                           |
| `>`        | number or ISO date string                  | Greater than — numeric or date comparison.                                 |
| `=>`       | number or ISO date string                  | Greater than or equal — numeric or date comparison.                        |
| `in`       | **array** of strings, numbers, or integers | Membership — field value matches any entry in the array.                   |
| `not_in`   | **array** of strings, numbers, or integers | Negated membership — field value matches none of the entries in the array. |
| `contains` | string                                     | Substring match — field value contains `value`.                            |

<Note>
  This operator set applies to **this autocomplete endpoint's `filters`
  parameter only**. `POST /person/search` uses a different set — it rejects
  `contains`; use `(.)` (all-words), `[.]` (exact phrase), `(!)` (negation),
  or `has_all` there. See the
  [Person Search operator reference](/person-docs/search/reference#filter-operator-reference).
</Note>

<Tip>
  Pass values with the JSON type that matches the underlying field: `"value":
        10000` for numeric fields, `"value": true` for booleans, and strings for
  text fields. `in` and `not_in` require a JSON array — a comma-separated
  string will return a 400.
</Tip>

### Request parameters

<Warning>
  **Operator footguns.** Use `=>` for greater-than-or-equal and `=<` for
  less-than-or-equal — these are **not** `>=` and `<=`. `in` / `not_in`
  require JSON arrays (not comma-separated strings).
</Warning>

| Parameter | Type    | Required | Description                                                                                                                                                                                  |
| --------- | ------- | -------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `field`   | string  | Yes      | Dataset field whose values you want suggested. Must be an **autocomplete-enabled field** — see [Autocomplete-enabled fields](#autocomplete-enabled-fields). Unsupported fields return `400`. |
| `query`   | string  | Yes      | Partial text to match against indexed values. Pass `""` to retrieve the top values for the field by frequency.                                                                               |
| `limit`   | integer | No       | Maximum number of suggestions to return. Minimum `1`, maximum `100`, default `20`.                                                                                                           |
| `filters` | object  | No       | Optional scope for the autocomplete computation. Pass either a single `AutocompleteFilterCondition` or a nested `AutocompleteFilterConditionGroup`.                                          |

#### `AutocompleteFilterCondition`

| Field   | Type                                       | Required | Description                                                                                                                                                                                  |
| ------- | ------------------------------------------ | -------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `field` | string                                     | Yes      | Dataset field to filter on. Can be any [Person Search](/person-docs/search/introduction) filter field — **this scope is broader than the autocomplete allowlist** for the top-level `field`. |
| `type`  | string (enum)                              | Yes      | One of [the supported operators](#supported-operators): `=`, `!=`, `<`, `=<`, `>`, `=>`, `in`, `not_in`, `contains`.                                                                         |
| `value` | string, number, integer, boolean, or array | Yes      | Scalar for comparison operators; JSON array of strings/numbers/integers for `in` and `not_in`. Match the JSON type to the underlying field's type.                                           |

#### `AutocompleteFilterConditionGroup`

| Field        | Type          | Required | Description                                                                                                                    |
| ------------ | ------------- | -------- | ------------------------------------------------------------------------------------------------------------------------------ |
| `op`         | string (enum) | Yes      | `"and"` or `"or"`.                                                                                                             |
| `conditions` | array         | Yes      | One or more `AutocompleteFilterCondition` items or nested `AutocompleteFilterConditionGroup` items. Must contain at least one. |

### Autocomplete-enabled fields

The top-level `field` in a Person Autocomplete request (the field whose
values you want suggested) must come from a **fixed allowlist** of
autocomplete-enabled dataset fields. Not every Person Search field is
autocomplete-enabled.

The `filters.field` is different: it can be any dataset field that
[Person Search](/person-docs/search/introduction) accepts as a filter, not only the
autocomplete allowlist. So you can filter autocomplete results on a broader
set of fields than you can autocomplete on directly.

<Note>
  The tables below are a **documented subset** of the autocomplete allowlist.
  They cover the fields most useful for building filter dropdowns, but they
  are **not exhaustive**. If a field you need is not listed, treat its support
  as unknown until you verify it — the safest way to confirm is to call the
  endpoint with that field and check whether you get a `400` error. See
  [Verify the live list](#verify-the-live-list) below for the debug-only live
  source.
</Note>

<Note>
  **`company_name` vs `name` for employers (current behavior).** For
  autocomplete, use `experience.employment_details.current.name` — the
  `company_name` variant is rejected in autocomplete scope. For
  `/person/search` filters, both `current.name` and `current.company_name` are
  accepted as aliases. In response payloads, the current employer appears
  under the `name` key.
</Note>

#### Common supported fields

<Tabs>
  <Tab title="Current employment">
    | Field                                                          | What it discovers               |
    | -------------------------------------------------------------- | ------------------------------- |
    | `experience.employment_details.current.title`                  | Current job titles              |
    | `experience.employment_details.current.name`                   | Current employer names          |
    | `experience.employment_details.current.seniority_level`        | Seniority level buckets         |
    | `experience.employment_details.current.function_category`      | Job function                    |
    | `experience.employment_details.current.company_industries`     | Current employer industries     |
    | `experience.employment_details.current.company_type`           | Current employer type           |
    | `experience.employment_details.current.company_hq_location`    | Current employer HQ location    |
    | `experience.employment_details.current.company_website_domain` | Current employer website domain |
    | `experience.employment_details.current.employment_type`        | Current employment type         |
  </Tab>

  <Tab title="Past employment">
    | Field                                                       | What it discovers            |
    | ----------------------------------------------------------- | ---------------------------- |
    | `experience.employment_details.past.title`                  | Past job titles              |
    | `experience.employment_details.past.name`                   | Past employer names          |
    | `experience.employment_details.past.seniority_level`        | Past seniority level buckets |
    | `experience.employment_details.past.function_category`      | Past job function            |
    | `experience.employment_details.past.company_type`           | Past employer type           |
    | `experience.employment_details.past.company_hq_location`    | Past employer HQ location    |
    | `experience.employment_details.past.company_website_domain` | Past employer website domain |
    | `experience.employment_details.past.employment_type`        | Past employment type         |
  </Tab>

  <Tab title="Profile & location">
    | Field                                     | What it discovers          |
    | ----------------------------------------- | -------------------------- |
    | `basic_profile.name`                      | Person names               |
    | `basic_profile.first_name`                | Person first names         |
    | `basic_profile.last_name`                 | Person last names          |
    | `basic_profile.headline`                  | Profile headlines          |
    | `basic_profile.languages`                 | Spoken languages           |
    | `basic_profile.location.raw`              | Raw location strings       |
    | `basic_profile.location.full_location`    | Full location strings      |
    | `basic_profile.location.city`             | Cities                     |
    | `basic_profile.location.state`            | States / regions           |
    | `basic_profile.location.country`          | Countries                  |
    | `basic_profile.location.continent`        | Continents                 |
    | `professional_network.location.city`      | Profile network cities     |
    | `professional_network.location.state`     | Profile network states     |
    | `professional_network.location.country`   | Profile network countries  |
    | `professional_network.location.continent` | Profile network continents |
    | `professional_network.open_to_cards`      | Open-to signal codes       |
  </Tab>

  <Tab title="Education, skills & more">
    | Field                                 | What it discovers      |
    | ------------------------------------- | ---------------------- |
    | `education.schools.school`            | Schools / universities |
    | `education.schools.degree`            | Degrees                |
    | `education.schools.field_of_study`    | Fields of study        |
    | `skills.professional_network_skills`  | Skills                 |
    | `certifications.name`                 | Certification names    |
    | `certifications.issuing_organization` | Certification issuers  |
    | `honors.title`                        | Honors and awards      |
  </Tab>

  <Tab title="Closed-enum fields">
    These fields have a **fixed, known value space**. An empty `query` returns
    the full enum in declaration order. They're useful when you need the exact
    set of accepted values for a filter dropdown — for example, populating an
    "open to" picker or an employment-type chip group.

    | Field             | What it discovers      | Returned values                                                  |
    | ----------------- | ---------------------- | ---------------------------------------------------------------- |
    | `open_to_cards`   | Open-to signal codes   | `CAREER_INTEREST`, `HIRING_MANAGER`, `VOLUNTEERING`              |
    | `employment_type` | Employment type labels | `Full-time`, `Part-time`, `Internship`, and other indexed labels |

    <Tip>
      `professional_network.open_to_cards` is an alias of `open_to_cards` — both
      return the same suggestions. Use whichever spelling matches the filter path
      on `/person/search`.
    </Tip>
  </Tab>
</Tabs>

#### Verify the live list

Call the endpoint with a deliberately invalid `field`. The `400` response
lists every currently accepted field in its error `message`:

<CodeGroup>
  ```bash Request theme={"theme":"vitesse-black"}
  curl --request POST \
    --url https://api.crustdata.com/person/search/autocomplete \
    --header 'authorization: Bearer YOUR_API_KEY' \
    --header 'content-type: application/json' \
    --header 'x-api-version: 2025-11-01' \
    --data '{
      "field": "current_title",
      "query": "",
      "limit": 1
    }'
  ```

  ```json Response (abbreviated) theme={"theme":"vitesse-black"}
  {
      "error": {
          "type": "invalid_request",
          "message": "Field 'current_title' is not supported on scope 'person'. Valid fields: basic_profile.city, basic_profile.continent, basic_profile.country, ..., experience.employment_details.current.function_category, experience.employment_details.current.title, ..., skills.professional_network_skills, state",
          "metadata": []
      }
  }
  ```
</CodeGroup>

### Implementation tips for UI builders

<Tip>
  * **Debounce** autocomplete calls to avoid one request per keystroke — 150–300 ms on input idle works well for typeahead UIs.
  * **Drop blank values.** If `""` is returned as the top suggestion, remove it before rendering the dropdown.
  * **Handle casing variants carefully.** Suggestions like `"VP"` and `"vp"` are **distinct indexed values**. Only merge them into a single UI option if you intentionally want normalized grouping — and if you do, preserve the underlying raw values and expand them in the eventual Person Search filter using `in`, for example `{"type": "in", "value": ["VP", "vp"]}`. If the UI needs exact-value selection, keep them as separate options.
  * **Cap `limit`.** Most dropdowns need 5–15 options. Lower `limit` reduces payload size and gives faster responses.
  * **Cache top-values lookups.** Empty-`query` calls that seed filter dropdowns rarely change — cache them client-side or at the edge.
</Tip>

### Errors

| Status | Meaning                                                                                                                                          |
| ------ | ------------------------------------------------------------------------------------------------------------------------------------------------ |
| `400`  | Invalid request — unsupported `field`, missing required field, a wrong `value` shape (for example a comma string for `in`), or a malformed body. |
| `401`  | Unauthorized — the `Authorization` header is missing, malformed, or contains an invalid API key.                                                 |
| `500`  | Internal server error — retry after a short delay.                                                                                               |

Note: a `query` that matches nothing is **not** an error — the endpoint
returns `{"suggestions": []}` with a 200 status. Only use 4xx/5xx handling
for actual request or server failures.

<CodeGroup>
  ```json 400 — Unsupported field theme={"theme":"vitesse-black"}
  {
      "error": {
          "type": "invalid_request",
          "message": "Field 'current_title' is not supported on scope 'person'. Valid fields: basic_profile.city, basic_profile.continent, ..., experience.employment_details.current.function_category, experience.employment_details.current.title, ..., skills.professional_network_skills, state",
          "metadata": []
      }
  }
  ```

  ```json 400 — Wrong value shape for in operator theme={"theme":"vitesse-black"}
  {
      "error": {
          "type": "invalid_request",
          "message": "Failed to get autocomplete suggestions: IN operator requires list or tuple value, got: <class 'str'>",
          "metadata": []
      }
  }
  ```

  ```json 401 — Invalid API key theme={"theme":"vitesse-black"}
  {
      "message": "Invalid API key in request"
  }
  ```
</CodeGroup>

### API reference summary

| Detail              | Value                                                                          |
| ------------------- | ------------------------------------------------------------------------------ |
| **Endpoint**        | `POST /person/search/autocomplete`                                             |
| **Auth**            | Bearer token + `x-api-version: 2025-11-01`                                     |
| **Required params** | `field`, `query`                                                               |
| **Optional params** | `limit` (default: 20, max: 100), `filters`                                     |
| **Response**        | `{ "suggestions": [{ "value": "..." }] }`                                      |
| **Empty result**    | `200` with `"suggestions": []`                                                 |
| **Errors**          | `400` (unsupported field or bad value), `401` (bad auth), `500` (server error) |

See the [full API reference](/openapi-specs/2025-11-01/introduction) for
the complete OpenAPI schema.

***

## What to do next

* **Try more patterns** — see [Examples](#examples) for most-common values, filtered suggestions, and the Autocomplete → Search workflow.
* **Reference** — see [Reference](#reference) for operators, request parameters, autocomplete-enabled fields, implementation tips, and errors.
* **Search for people** — use discovered values in [Person Search](/person-docs/search/introduction).
* **Enrich matches** — use [Person Enrich](/person-docs/enrichment/introduction) to get full profiles after you find people.
