---
title: "Suggest person filter values"
method: POST
path: "/api/people/suggest"
tags: ["people"]
---

# Suggest person filter values

`POST /api/people/suggest`

## Request

- Base URL: `https://beta.getsales.io/playtables/v1`
- URL: `https://beta.getsales.io/playtables/v1/api/people/suggest`
- Auth: HTTP bearer and API key in header `Team-SID`

Facet helper for building people filters - distinct values + row counts for one field within a filter scope (ES aggregation). field: company_name | tag_sids; term narrows by prefix/infix; typical scope filter = { playtable_sid: { eq } }. tag_sids returns tag sids with counts - resolve names via the tags tools. Feed a picked value into search filter eq/in. Profile facets (position, location, …) are playtable field values - facet via the cell-value tooling, not here.

Contract:
- MCP tool `suggest_person_filter_values`, registry package `mcp.playtables/people`, mount `playtables.people`.
- Operation `action`, response envelope `action`.
- Flags: read only.

## Request body

- SuggestPersonFilterValuesRequest: Request body of `suggest_person_filter_values`.
  - `field` 'company_name' | 'tag_sids', required: Facet field: company_name (the resolved company name) | tag_sids (returns tag sids).
  - `term` string: Prefix/infix narrowing; omit for top values.
  - `filter` object: Scope - typically { playtable_sid: { eq: … } }.
    - `sid` object: Prefix-validated cr_pp_ sid(s).
      - `eq` string: Person sid (cr_pp_…).
      - `in` string[]
    - `playtable_sid` object: THE table context - every table view passes { eq: <table> }.
      - `eq` string
      - `in` string[]
    - `pipeline_stage_category` object: The stage's funnel bucket (one of seven), expanded on the server into the team's person stage sids of those categories: ask by name, never resolve stages. eq approaching = we reached out, nothing came back; in [engaging, positive] = something came back.
      - `eq` 'cold' | 'approaching' | 'engaging' | 'positive' | 'nurture' | 'negative' | 'disqualified'
      - `in` string[]
    - `company_sid` object
      - `eq` string
      - `in` string[]
      - `is_null` boolean
    - `data_source_sid` object: Import provenance.
      - `eq` string
      - `in` string[]
      - `is_null` boolean
    - `status` object
      - `eq` 'ok' | 'failed_validation' | 'no_contact_data' | 'duplicate' | 'stoplisted'
      - `ne` 'ok' | 'failed_validation' | 'no_contact_data' | 'duplicate' | 'stoplisted'
      - `in` string[]
      - `nin` string[]
    - `duplicate_of_sid` object: The copies of a primary: { eq: <primary sid> }. is_null:true = rows that are not flagged duplicates.
      - `eq` string: Person sid (cr_pp_…).
      - `in` string[]
      - `is_null` boolean
    - `linkedin_status` object
      - `eq` 'need_enrichment' | 'enrichment_failed' | 'no_data' | 'blocked' | 'ok'
      - `ne` 'need_enrichment' | 'enrichment_failed' | 'no_data' | 'blocked' | 'ok'
      - `in` string[]
      - `nin` string[]
    - `email_status` object
      - `eq` 'need_search' | 'no_data' | 'bounced' | 'ok' | 'catch_all' | 'unverified'
      - `ne` 'need_search' | 'no_data' | 'bounced' | 'ok' | 'catch_all' | 'unverified'
      - `in` string[]
      - `nin` string[]
      - `is_null` boolean
    - `phone_status` object
      - `eq` 'need_search' | 'no_data' | 'ok'
      - `ne` 'need_search' | 'no_data' | 'ok'
      - `in` string[]
      - `nin` string[]
      - `is_null` boolean
    - `tag_sids` object: Array-overlap semantics (any of) - in matches rows whose tag array overlaps the list; nin answers the complement, untagged rows included.
      - `in` string[]
      - `nin` string[]
    - `signals` object[]: ES-only. Named signals of the person, all must hold. The server expands a name into its keyword and clock range: never compose them. A bare entry takes the catalog default age, age_days moves it. A thread-only name is a 422 (ask search_conversations).
      - `key` 'awaiting_reply' | 'opened_not_replied' | 'clicked_not_replied' | 'multi_opened' | 'accepted_not_replied' | 'note_read_not_replied' | 'reacted_not_replied' | 'invited_us' | 'followed_us' | 'lead_messaged_first' | 'unanswered_inbound' | 'draft_pending' | 'escalated_open' | 'task_overdue' | 'went_quiet' | 'reactivated' | 'invite_pending' | 'connection_removed' | 'blocked_us' | 'deleted_message' | 'bounced' | 'bounced_hard' | 'complained' | 'booking_link_sent' | 'objective_reached' | 'viewed_our_profile' | 'visited_our_site' | 'visited_not_replied' | 'visited_key_page' | 'multi_visited' | 'submitted_form' | 'company_visited_our_site' | 'no_people' | 'thin_coverage' | 'nobody_reached' | 'no_engagement' | 'no_reply' | 'exhausted' | 'dormant' | 'dm_missing', required: A catalog signal name. Thread and person names: awaiting_reply (our message is the last), opened_not_replied and clicked_not_replied (our email opened or its link clicked, no reply), multi_opened (3+ opens), accepted_not_replied (invite accepted, nothing after), note_read_not_replied (the accept delivered our invite note, no reply), reacted_not_replied (an emoji on our message, no reply), invited_us (their invitation to us, unanswered), followed_us, lead_messaged_first (an inbound thread), unanswered_inbound, draft_pending (an AI draft awaits approval), escalated_open (handed to a person, task open), task_overdue, went_quiet (they had replied, then nothing), reactivated (an inbound after 30+ quiet days), invite_pending (our invite out, neither accepted nor withdrawn), connection_removed, blocked_us, deleted_message, bounced, bounced_hard (the address is gone), complained, booking_link_sent, objective_reached (the live dialog landed its goal), viewed_our_profile. Website names: visited_our_site, visited_not_replied, visited_key_page (a page the team marked key), multi_visited, submitted_form, company_visited_our_site (someone from the company, nobody recognized; a person's and a company's). Account names, companies only (dormant also a person's): no_people (nobody to work), thin_coverage (under 3 people to work), nobody_reached, no_engagement (touched, nothing came back), no_reply (touched, no reply), exhausted (everyone nurture or negative), dormant (touched once, quiet since), dm_missing (a Wrong Decision Maker named, no positive person left). Tracking facts are private: never tell the lead (submitted_form excepted).
      - `age_days` integer: At least this many days on the signal's clock (0 = any). Defaults when omitted: 1 visited_not_replied; 3 awaiting_reply and the *_not_replied names; 14 went_quiet, invite_pending; 30 no_engagement, no_reply; 180 dormant; the rest any age.
    - `ln_member_id` object: Exact identifier.
      - `eq` string
      - `in` string[]
      - `is_null` boolean
    - `ln_id` object: Exact raw profile URN.
      - `eq` string
      - `in` string[]
      - `is_null` boolean
    - `sn_id` object: Exact raw Sales Navigator URN.
      - `eq` string
      - `in` string[]
      - `is_null` boolean
    - `ln_nickname` object: Exact vanity slug (lowercased); use q for fuzzy.
      - `eq` string
      - `in` string[]
      - `is_null` boolean
    - `work_email` object: is_null:true = coverage gap.
      - `eq` string
      - `in` string[]
      - `is_null` boolean
    - `personal_email` object
      - `eq` string
      - `in` string[]
      - `is_null` boolean
    - `q` string: Free text (ES people index) over the resolved name and company name, the emails and the slug. Filter a company by company_sid.
    - `created_at` object: ISO 8601 range; combine bounds in one object.
      - `gte` string
      - `lte` string
      - `gt` string
      - `lt` string
    - `updated_at` object
      - `gte` string
      - `lte` string
      - `gt` string
      - `lt` string
    - `deleted_at` object: Default scope is { is_null: true } (live rows).
      - `gte` string
      - `lte` string
      - `is_null` boolean
  - `limit` integer: 1..50, default 20.

## Response `200`

`action` success envelope.

- SuggestPersonFilterValuesResponse
  - `success` true, required
  - `operation` 'action', required
  - `action` string, required: kebab-case verb; matches the route segment.
  - `item` unknown, required
  - `result` object, required
    - `suggestions` object[], required
      - `value` string, required: Distinct field value (a tag sid when field=tag_sids).
      - `count` integer, required: Matching rows within the filter scope.
  - `meta` object, required
    - `trace_id` string, required: UUID v7; same 128-bit value as the X-Trace-Id header.
    - `span_id` string, required: 16 hex chars, root span of this request.
    - `timestamp` string, required: ISO 8601 UTC (Y-m-dTH:i:sZ), response time.
    - `duration_ms` integer, required: Server-side wall clock.
    - `team_sid` string, nullable: The team this call ran in (the token team, or the team_sid override). Null when unauthenticated; absent from pre-2026-08-20 backends.
    - `actor_type` string, nullable: user | agent | api_key | system. Null when unauthenticated; absent from pre-2026-08-20 backends.

## Other responses

- `4XX`: MCP error envelope. `error.code` is one of validation_failed, nothing_to_update, not_found, relation_not_found, invalid_transition, limit_exceeded, payment_required, duplicate_rejected, conflict, delete_blocked, unauthorized, forbidden, rate_limited, not_implemented.
- `5XX`: MCP error envelope with `error.code` internal_error or service_unavailable.

---

[API](https://skmtc.dev/getsales/apis/getsales-public-contract-gs-service-playtables.md) - [All operations](https://skmtc.dev/getsales/apis/getsales-public-contract-gs-service-playtables/llms.txt) - [OpenAPI document](https://skmtc.dev/getsales/apis/getsales-public-contract-gs-service-playtables/revisions/aa394506515d?raw)
