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

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

Reference material for [Person Autocomplete](/person-docs/autocomplete/introduction):
contract vs current behavior, supported filter operators, request
parameters, autocomplete-enabled fields, implementation tips for UI
builders, and errors.

For walk-through examples, see
[Person Autocomplete](/person-docs/autocomplete/introduction) and
[Examples](/person-docs/autocomplete/examples).

***

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

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