Find people by their attributes, using a boolean rule tree.
Searches the same pool the list endpoint serves (your workspace’s people
plus the platform library), and returns the same paginated envelope.
The rule tree
A rule is a single node. A node is either a leaf or a group, never
both:
A leaf tests one attribute: {"field": {"source": ..., "key": ...}, "operator": ..., "value": ...}. Copy source and key from the
attribute’s filter block in GET .../people/schema; that endpoint is
the authoritative vocabulary, and an attribute or operator it does not
list is refused with a 422 rather than matching nothing.
A group combines nodes: {"op": "and" | "or" | "not", "conditions": [...]}.
Boolean semantics, exactly
A group’s op applies to its OWN conditions and to nothing else. and
matches a person satisfying every condition in that group; or matches
a person satisfying at least one; not takes exactly one condition
and matches people who do not satisfy it. Groups nest, so a group inside
another group is evaluated on its own first and its result is then one
input to the parent’s operator. There is no precedence to remember and no
implicit combination anywhere: two conditions are only ever joined by the
op of the group holding them.
A worked example
“Nurses in Sweden, plus teachers in Norway” is two AND-groups joined by an
OR. Note that the country is repeated in both groups: the outer or does
not distribute over anything, so a condition placed outside the groups
would not apply to either.
is_not_null matches people who have a value for an attribute, and
is_null matches people who do not. Reach for these rather than comparing
against an empty string: an attribute nobody filled in holds no value at
all, and it satisfies no ordinary comparison, not even a negated one.
Limits, and how a rule is refused
A rule may nest groups at most 2 levels deep, hold at most 15
conditions in any one group, and 25 in total.
Both refusals are a 422 carrying an error_kind, and they have different
fixes:
search_rule_too_complex: past one of those caps. The detail names the
offending count and the limit. Combining values with in costs one
condition instead of one per value, and is the usual fix.
search_rule_invalid: the tree is malformed, or it names an attribute,
source or operator this API does not publish. The detail names the
offender, and GET .../people/schema is the vocabulary it was checked
against.
A malformed request BODY (rather than a bad rule) is the ordinary
validation 422 with the field-level envelope, which is why this
operation’s 422 documents either shape.
Saved segments
Segments live in the ish app and are not exposed here. A segment IS a rule,
so the way to use one is to send its rule as the rule on this request:
that is how the ish console itself applies them.
Workspace API key as a bearer token: Authorization: Bearer ish_sk_live_.... Keys are workspace-scoped machine principals minted in Settings > Developers (shown once at mint). Scopes: sessions:run (create a session, submit turns, close), sessions:read (read the session and its decision trace), environments:read and environments:write (manage the workspace's registered environments), tasks:read and tasks:write (manage the workspace's registered tasks), people:read and people:write (the people the workspace can run a session for), and usage:read (the workspace's own consumption, spend limits and rate-limit budgets). A key is minted with sessions:run, sessions:read, and tasks:read by default; every other scope must be requested, people:read and usage:read included. An ish user access token also works on the same header for personal scripts.
false (the default) searches live people; true searches the archive instead. The two sets are disjoint, so this selects which one you are searching rather than widening the search.
Opaque keyset cursor for the next page (pass as after); null on the final page.
{"docsConfig":{"theme":"mint","$schema":"https://mintlify.com/docs.json","name":"ish","description":"Documentation for the ish CLI and MCP server. Simulate a visit and read the reactions before you ship.","colors":{"primary":"#C8623F","light":"#D87A55","dark":"#262220"},"logo":{"light":"https://mintcdn.com/ish/4MaJn6-B7_NnPAml/logo/light.svg?fit=max\u0026auto=format\u0026n=4MaJn6-B7_NnPAml\u0026q=85\u0026s=f0edab6b74c19bec95794ee94d7270c2","dark":"https://mintcdn.com/ish/4MaJn6-B7_NnPAml/logo/dark.svg?fit=max\u0026auto=format\u0026n=4MaJn6-B7_NnPAml\u0026q=85\u0026s=da9e886222890dc4edeaf5b77b455102"},"favicon":{"light":"https://mintcdn.com/ish/4MaJn6-B7_NnPAml/favicon.svg?fit=max\u0026auto=format\u0026n=4MaJn6-B7_NnPAml\u0026q=85\u0026s=871b7f0a040fb0e8c3293911bcbfd37d","dark":"https://mintcdn.com/ish/4MaJn6-B7_NnPAml/favicon-dark.svg?fit=max\u0026auto=format\u0026n=4MaJn6-B7_NnPAml\u0026q=85\u0026s=8915499d3e98ef136443c3c38b96e4b9"},"appearance":{"default":"system"},"background":{"color":{"light":"#FDFCFB","dark":"#1A1816"}},"navbar":{"links":[{"href":"https://app.ishlabs.io","label":"Sign in"}],"primary":{"type":"button","label":"Get ish free","href":"https://app.ishlabs.io"}},"footer":{"socials":{"github":"https://github.com/ishlabs"},"links":[{"header":"Product","items":[{"label":"ishlabs.io","href":"https://ishlabs.io"},{"label":"Pricing","href":"https://ishlabs.io/pricing"},{"label":"Sign in","href":"https://app.ishlabs.io"}]}]},"fonts":{"heading":{"family":"Inter"},"body":{"family":"Inter"}},"contextual":{"options":["copy","view","chatgpt","claude","mcp","cursor","vscode"],"display":"header"},"styling":{"latex":false},"navigation":{"global":{"anchors":[{"anchor":"GitHub","icon":"github","href":"https://github.com/ishlabs"},{"anchor":"ishlabs.io","icon":"globe","href":"https://ishlabs.io"}]},"pages":[]}},"deployment":{"deploymentMetadataValue":{"subdomain":"ish","hasAudioNarration":false,"actualSubdomain":"ish","customDomains":["docs.ishlabs.io"],"gitSource":{"type":"github","owner":"ishlabs","repo":"docs","deployBranch":"main","contentDirectory":"","isPrivate":false,"mountPath":"","label":""},"feedback":{"thumbs":false},"entitlements":{"AI_CHAT":{"status":"DISABLED"}},"buildId":"6af0209f0311aab340dbb5c0","clientVersion":"0.0.4094","searchFilterCounts":[{"language":"default","tag":"Guides","count":45},{"language":"default","tag":"API","count":42},{"language":"default","tag":"API reference","count":28},{"language":"default","tag":"CLI Reference","count":28},{"language":"default","tag":"Core concepts","count":26},{"language":"default","tag":"MCP Reference","count":21},{"language":"default","tag":"Commands","count":20},{"language":"default","tag":"Overview","count":15},{"language":"default","tag":"Tools","count":13},{"language":"default","tag":"How-to guides","count":9}]},"assistantConfig":{"enableAskAiButton":false,"enableStarterQuestions":false,"enableContextualStarterQuestions":false,"enableAskAiSearchBar":true},"basePath":"","hasChatPermissions":false,"hasWebMcpPermissions":false,"toggles":[{"name":"kill-isr","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"agent-mintlify-slack","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"agent-integrations-settings","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"rbac-expansion","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"automations-pr-grouping","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"custom-prefix","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"analytics-v7","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"user-flows-analytics","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"no-publish-flow","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"workos-onboarding","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"llms-txt-v2","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"snapshot-serving-live","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"stripTemperatureMiddleware","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"support-platform-pylon-zendesk","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"snapshot-serving","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"instant-rollback","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"granular-notifications-server","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"granular-notifications","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"automations-fable","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"fixed-ai-action-pricing","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"automation-resolve-merge-conflict","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"scoped-publishing","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"mintql","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"page-level-analytics","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"editor-version-history-v2","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"billing-page-v2","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"full-page-search","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"workspace-projects","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"assistant-v5","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"fork-pr-previews","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"revalidation-jwt","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"workos-sso-scim","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"hobby-abuse-scan","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"dashboard-inbox","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"workos-signup","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"turbopuffer-dual-write","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"workos-enabled","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"approve-review-flow","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"editor-metadata","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"sso-setup-deadline-banner","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"turbopuffer-serve","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"live-agents","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"comment-mode","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false}],"googleFontsInlined":false},"customCss":[{"filePath":"style.css","content":"[data-component-part=\"card-icon\"] svg{background-color:#262220!important}html.dark [data-component-part=\"card-icon\"] svg{background-color:#e8e3de!important}html.dark img[src*=\"/logos/\"]{filter:invert(0.91) brightness(1.03)}#content-area a[href]>div:hover,.ish-card:hover{border-color:#d87a55;transition:border-color 0.15s ease, box-shadow 0.15s ease}"}],"page":{"pagePath":"api/reference/people/search-people","slug":"/api/reference/people/search-people","pageMetadata":{"title":"Search People","description":"Find people by their attributes, using a boolean rule tree.\n\nSearches the same pool the list endpoint serves (your workspace's people\nplus the platform library), and returns the same paginated envelope.\n\n## The rule tree\n\nA rule is a single node. A node is either a **leaf** or a **group**, never\nboth:\n\n- A **leaf** tests one attribute: `{\"field\": {\"source\": ..., \"key\": ...},\n \"operator\": ..., \"value\": ...}`. Copy `source` and `key` from the\n attribute's `filter` block in `GET .../people/schema`; that endpoint is\n the authoritative vocabulary, and an attribute or operator it does not\n list is refused with a `422` rather than matching nothing.\n- A **group** combines nodes: `{\"op\": \"and\" | \"or\" | \"not\", \"conditions\":\n [...]}`.\n\n## Boolean semantics, exactly\n\nA group's `op` applies to its OWN `conditions` and to nothing else. `and`\nmatches a person satisfying **every** condition in that group; `or` matches\na person satisfying **at least one**; `not` takes **exactly one** condition\nand matches people who do not satisfy it. Groups nest, so a group inside\nanother group is evaluated on its own first and its result is then one\ninput to the parent's operator. There is no precedence to remember and no\nimplicit combination anywhere: two conditions are only ever joined by the\n`op` of the group holding them.\n\n## A worked example\n\n\"Nurses in Sweden, plus teachers in Norway\" is two AND-groups joined by an\nOR. Note that the country is repeated in both groups: the outer `or` does\nnot distribute over anything, so a condition placed outside the groups\nwould not apply to either.\n\n```json\n{\n \"rule\": {\n \"op\": \"or\",\n \"conditions\": [\n {\"op\": \"and\", \"conditions\": [\n {\"field\": {\"source\": \"demographic\", \"key\": \"occupation\"},\n \"operator\": \"eq\", \"value\": \"nurse\"},\n {\"field\": {\"source\": \"demographic\", \"key\": \"country\"},\n \"operator\": \"eq\", \"value\": \"Sweden\"}\n ]},\n {\"op\": \"and\", \"conditions\": [\n {\"field\": {\"source\": \"demographic\", \"key\": \"occupation\"},\n \"operator\": \"eq\", \"value\": \"teacher\"},\n {\"field\": {\"source\": \"demographic\", \"key\": \"country\"},\n \"operator\": \"eq\", \"value\": \"Norway\"}\n ]}\n ]\n },\n \"pagination\": {\"limit\": 25}\n}\n```\n\n## Testing whether an attribute is set\n\n`is_not_null` matches people who have a value for an attribute, and\n`is_null` matches people who do not. Reach for these rather than comparing\nagainst an empty string: an attribute nobody filled in holds no value at\nall, and it satisfies no ordinary comparison, not even a negated one.\n\n## Limits, and how a rule is refused\n\nA rule may nest groups at most **2** levels deep, hold at most **15**\nconditions in any one group, and **25** in total.\n\nBoth refusals are a `422` carrying an `error_kind`, and they have different\nfixes:\n\n- `search_rule_too_complex`: past one of those caps. The detail names the\n offending count and the limit. Combining values with `in` costs one\n condition instead of one per value, and is the usual fix.\n- `search_rule_invalid`: the tree is malformed, or it names an attribute,\n source or operator this API does not publish. The detail names the\n offender, and `GET .../people/schema` is the vocabulary it was checked\n against.\n\nA malformed request BODY (rather than a bad rule) is the ordinary\nvalidation `422` with the field-level envelope, which is why this\noperation's `422` documents either shape.\n\n## Saved segments\n\nSegments live in the ish app and are not exposed here. A segment IS a rule,\nso the way to use one is to send its rule as the `rule` on this request:\nthat is how the ish console itself applies them.","deprecated":null,"version":null,"openapi":"/api/openapi.public.json post /api/v1/workspaces/{workspace_id}/people/search","href":"/api/reference/people/search-people","autogeneratedByOpenApi":true},"description":{"compiledSource":"\"use strict\";\nconst {Fragment: _Fragment, jsx: _jsx, jsxs: _jsxs} = arguments[0];\nconst {useMDXComponents: _provideComponents} = arguments[0];\nfunction _createMdxContent(props) {\n const _components = {\n code: \"code\",\n h2: \"h2\",\n li: \"li\",\n p: \"p\",\n pre: \"pre\",\n span: \"span\",\n strong: \"strong\",\n ul: \"ul\",\n ..._provideComponents(),\n ...props.components\n }, {CodeBlock} = _components;\n if (!CodeBlock) _missingMdxReference(\"CodeBlock\", true);\n return _jsxs(_Fragment, {\n children: [_jsx(_components.p, {\n children: \"Find people by their attributes, using a boolean rule tree.\"\n }), \"\\n\", _jsx(_components.p, {\n children: \"Searches the same pool the list endpoint serves (your workspace’s people\\nplus the platform library), and returns the same paginated envelope.\"\n }), \"\\n\", _jsx(_components.h2, {\n children: \"The rule tree\"\n }), \"\\n\", _jsxs(_components.p, {\n children: [\"A rule is a single node. A node is either a \", _jsx(_components.strong, {\n children: \"leaf\"\n }), \" or a \", _jsx(_components.strong, {\n children: \"group\"\n }), \", never\\nboth:\"]\n }), \"\\n\", _jsxs(_components.ul, {\n children: [\"\\n\", _jsxs(_components.li, {\n children: [\"A \", _jsx(_components.strong, {\n children: \"leaf\"\n }), \" tests one attribute: \", _jsx(_components.code, {\n children: \"{\\\"field\\\": {\\\"source\\\": ..., \\\"key\\\": ...}, \\\"operator\\\": ..., \\\"value\\\": ...}\"\n }), \". Copy \", _jsx(_components.code, {\n children: \"source\"\n }), \" and \", _jsx(_components.code, {\n children: \"key\"\n }), \" from the\\nattribute’s \", _jsx(_components.code, {\n children: \"filter\"\n }), \" block in \", _jsx(_components.code, {\n children: \"GET .../people/schema\"\n }), \"; that endpoint is\\nthe authoritative vocabulary, and an attribute or operator it does not\\nlist is refused with a \", _jsx(_components.code, {\n children: \"422\"\n }), \" rather than matching nothing.\"]\n }), \"\\n\", _jsxs(_components.li, {\n children: [\"A \", _jsx(_components.strong, {\n children: \"group\"\n }), \" combines nodes: \", _jsx(_components.code, {\n children: \"{\\\"op\\\": \\\"and\\\" | \\\"or\\\" | \\\"not\\\", \\\"conditions\\\": [...]}\"\n }), \".\"]\n }), \"\\n\"]\n }), \"\\n\", _jsx(_components.h2, {\n children: \"Boolean semantics, exactly\"\n }), \"\\n\", _jsxs(_components.p, {\n children: [\"A group’s \", _jsx(_components.code, {\n children: \"op\"\n }), \" applies to its OWN \", _jsx(_components.code, {\n children: \"conditions\"\n }), \" and to nothing else. \", _jsx(_components.code, {\n children: \"and\"\n }), \"\\nmatches a person satisfying \", _jsx(_components.strong, {\n children: \"every\"\n }), \" condition in that group; \", _jsx(_components.code, {\n children: \"or\"\n }), \" matches\\na person satisfying \", _jsx(_components.strong, {\n children: \"at least one\"\n }), \"; \", _jsx(_components.code, {\n children: \"not\"\n }), \" takes \", _jsx(_components.strong, {\n children: \"exactly one\"\n }), \" condition\\nand matches people who do not satisfy it. Groups nest, so a group inside\\nanother group is evaluated on its own first and its result is then one\\ninput to the parent’s operator. There is no precedence to remember and no\\nimplicit combination anywhere: two conditions are only ever joined by the\\n\", _jsx(_components.code, {\n children: \"op\"\n }), \" of the group holding them.\"]\n }), \"\\n\", _jsx(_components.h2, {\n children: \"A worked example\"\n }), \"\\n\", _jsxs(_components.p, {\n children: [\"“Nurses in Sweden, plus teachers in Norway” is two AND-groups joined by an\\nOR. Note that the country is repeated in both groups: the outer \", _jsx(_components.code, {\n children: \"or\"\n }), \" does\\nnot distribute over anything, so a condition placed outside the groups\\nwould not apply to either.\"]\n }), \"\\n\", _jsx(CodeBlock, {\n numberOfLines: \"20\",\n language: \"json\",\n children: _jsx(_components.pre, {\n className: \"shiki shiki-themes github-light-default dark-plus\",\n style: {\n backgroundColor: \"#ffffff\",\n \"--shiki-dark-bg\": \"#0B0C0E\",\n color: \"#1f2328\",\n \"--shiki-dark\": \"#D4D4D4\"\n },\n language: \"json\",\n children: _jsxs(_components.code, {\n language: \"json\",\n numberOfLines: \"20\",\n children: [_jsx(_components.span, {\n className: \"line\",\n children: _jsx(_components.span, {\n style: {\n color: \"#1F2328\",\n \"--shiki-dark\": \"#D4D4D4\"\n },\n children: \"{\"\n })\n }), \"\\n\", _jsxs(_components.span, {\n className: \"line\",\n children: [_jsx(_components.span, {\n style: {\n color: \"#116329\",\n \"--shiki-dark\": \"#9CDCFE\"\n },\n children: \" \\\"rule\\\"\"\n }), _jsx(_components.span, {\n style: {\n color: \"#1F2328\",\n \"--shiki-dark\": \"#D4D4D4\"\n },\n children: \": {\"\n })]\n }), \"\\n\", _jsxs(_components.span, {\n className: \"line\",\n children: [_jsx(_components.span, {\n style: {\n color: \"#116329\",\n \"--shiki-dark\": \"#9CDCFE\"\n },\n children: \" \\\"op\\\"\"\n }), _jsx(_components.span, {\n style: {\n color: \"#1F2328\",\n \"--shiki-dark\": \"#D4D4D4\"\n },\n children: \": \"\n }), _jsx(_components.span, {\n style: {\n color: \"#0A3069\",\n \"--shiki-dark\": \"#CE9178\"\n },\n children: \"\\\"or\\\"\"\n }), _jsx(_components.span, {\n style: {\n color: \"#1F2328\",\n \"--shiki-dark\": \"#D4D4D4\"\n },\n children: \",\"\n })]\n }), \"\\n\", _jsxs(_components.span, {\n className: \"line\",\n children: [_jsx(_components.span, {\n style: {\n color: \"#116329\",\n \"--shiki-dark\": \"#9CDCFE\"\n },\n children: \" \\\"conditions\\\"\"\n }), _jsx(_components.span, {\n style: {\n color: \"#1F2328\",\n \"--shiki-dark\": \"#D4D4D4\"\n },\n children: \": [\"\n })]\n }), \"\\n\", _jsxs(_components.span, {\n className: \"line\",\n children: [_jsx(_components.span, {\n style: {\n color: \"#1F2328\",\n \"--shiki-dark\": \"#D4D4D4\"\n },\n children: \" {\"\n }), _jsx(_components.span, {\n style: {\n color: \"#116329\",\n \"--shiki-dark\": \"#9CDCFE\"\n },\n children: \"\\\"op\\\"\"\n }), _jsx(_components.span, {\n style: {\n color: \"#1F2328\",\n \"--shiki-dark\": \"#D4D4D4\"\n },\n children: \": \"\n }), _jsx(_components.span, {\n style: {\n color: \"#0A3069\",\n \"--shiki-dark\": \"#CE9178\"\n },\n children: \"\\\"and\\\"\"\n }), _jsx(_components.span, {\n style: {\n color: \"#1F2328\",\n \"--shiki-dark\": \"#D4D4D4\"\n },\n children: \", \"\n }), _jsx(_components.span, {\n style: {\n color: \"#116329\",\n \"--shiki-dark\": \"#9CDCFE\"\n },\n children: \"\\\"conditions\\\"\"\n }), _jsx(_components.span, {\n style: {\n color: \"#1F2328\",\n \"--shiki-dark\": \"#D4D4D4\"\n },\n children: \": [\"\n })]\n }), \"\\n\", _jsxs(_components.span, {\n className: \"line\",\n children: [_jsx(_components.span, {\n style: {\n color: \"#1F2328\",\n \"--shiki-dark\": \"#D4D4D4\"\n },\n children: \" {\"\n }), _jsx(_components.span, {\n style: {\n color: \"#116329\",\n \"--shiki-dark\": \"#9CDCFE\"\n },\n children: \"\\\"field\\\"\"\n }), _jsx(_components.span, {\n style: {\n color: \"#1F2328\",\n \"--shiki-dark\": \"#D4D4D4\"\n },\n children: \": {\"\n }), _jsx(_components.span, {\n style: {\n color: \"#116329\",\n \"--shiki-dark\": \"#9CDCFE\"\n },\n children: \"\\\"source\\\"\"\n }), _jsx(_components.span, {\n style: {\n color: \"#1F2328\",\n \"--shiki-dark\": \"#D4D4D4\"\n },\n children: \": \"\n }), _jsx(_components.span, {\n style: {\n color: \"#0A3069\",\n \"--shiki-dark\": \"#CE9178\"\n },\n children: \"\\\"demographic\\\"\"\n }), _jsx(_components.span, {\n style: {\n color: \"#1F2328\",\n \"--shiki-dark\": \"#D4D4D4\"\n },\n children: \", \"\n }), _jsx(_components.span, {\n style: {\n color: \"#116329\",\n \"--shiki-dark\": \"#9CDCFE\"\n },\n children: \"\\\"key\\\"\"\n }), _jsx(_components.span, {\n style: {\n color: \"#1F2328\",\n \"--shiki-dark\": \"#D4D4D4\"\n },\n children: \": \"\n }), _jsx(_components.span, {\n style: {\n color: \"#0A3069\",\n \"--shiki-dark\": \"#CE9178\"\n },\n children: \"\\\"occupation\\\"\"\n }), _jsx(_components.span, {\n style: {\n color: \"#1F2328\",\n \"--shiki-dark\": \"#D4D4D4\"\n },\n children: \"},\"\n })]\n }), \"\\n\", _jsxs(_components.span, {\n className: \"line\",\n children: [_jsx(_components.span, {\n style: {\n color: \"#116329\",\n \"--shiki-dark\": \"#9CDCFE\"\n },\n children: \" \\\"operator\\\"\"\n }), _jsx(_components.span, {\n style: {\n color: \"#1F2328\",\n \"--shiki-dark\": \"#D4D4D4\"\n },\n children: \": \"\n }), _jsx(_components.span, {\n style: {\n color: \"#0A3069\",\n \"--shiki-dark\": \"#CE9178\"\n },\n children: \"\\\"eq\\\"\"\n }), _jsx(_components.span, {\n style: {\n color: \"#1F2328\",\n \"--shiki-dark\": \"#D4D4D4\"\n },\n children: \", \"\n }), _jsx(_components.span, {\n style: {\n color: \"#116329\",\n \"--shiki-dark\": \"#9CDCFE\"\n },\n children: \"\\\"value\\\"\"\n }), _jsx(_components.span, {\n style: {\n color: \"#1F2328\",\n \"--shiki-dark\": \"#D4D4D4\"\n },\n children: \": \"\n }), _jsx(_components.span, {\n style: {\n color: \"#0A3069\",\n \"--shiki-dark\": \"#CE9178\"\n },\n children: \"\\\"nurse\\\"\"\n }), _jsx(_components.span, {\n style: {\n color: \"#1F2328\",\n \"--shiki-dark\": \"#D4D4D4\"\n },\n children: \"},\"\n })]\n }), \"\\n\", _jsxs(_components.span, {\n className: \"line\",\n children: [_jsx(_components.span, {\n style: {\n color: \"#1F2328\",\n \"--shiki-dark\": \"#D4D4D4\"\n },\n children: \" {\"\n }), _jsx(_components.span, {\n style: {\n color: \"#116329\",\n \"--shiki-dark\": \"#9CDCFE\"\n },\n children: \"\\\"field\\\"\"\n }), _jsx(_components.span, {\n style: {\n color: \"#1F2328\",\n \"--shiki-dark\": \"#D4D4D4\"\n },\n children: \": {\"\n }), _jsx(_components.span, {\n style: {\n color: \"#116329\",\n \"--shiki-dark\": \"#9CDCFE\"\n },\n children: \"\\\"source\\\"\"\n }), _jsx(_components.span, {\n style: {\n color: \"#1F2328\",\n \"--shiki-dark\": \"#D4D4D4\"\n },\n children: \": \"\n }), _jsx(_components.span, {\n style: {\n color: \"#0A3069\",\n \"--shiki-dark\": \"#CE9178\"\n },\n children: \"\\\"demographic\\\"\"\n }), _jsx(_components.span, {\n style: {\n color: \"#1F2328\",\n \"--shiki-dark\": \"#D4D4D4\"\n },\n children: \", \"\n }), _jsx(_components.span, {\n style: {\n color: \"#116329\",\n \"--shiki-dark\": \"#9CDCFE\"\n },\n children: \"\\\"key\\\"\"\n }), _jsx(_components.span, {\n style: {\n color: \"#1F2328\",\n \"--shiki-dark\": \"#D4D4D4\"\n },\n children: \": \"\n }), _jsx(_components.span, {\n style: {\n color: \"#0A3069\",\n \"--shiki-dark\": \"#CE9178\"\n },\n children: \"\\\"country\\\"\"\n }), _jsx(_components.span, {\n style: {\n color: \"#1F2328\",\n \"--shiki-dark\": \"#D4D4D4\"\n },\n children: \"},\"\n })]\n }), \"\\n\", _jsxs(_components.span, {\n className: \"line\",\n children: [_jsx(_components.span, {\n style: {\n color: \"#116329\",\n \"--shiki-dark\": \"#9CDCFE\"\n },\n children: \" \\\"operator\\\"\"\n }), _jsx(_components.span, {\n style: {\n color: \"#1F2328\",\n \"--shiki-dark\": \"#D4D4D4\"\n },\n children: \": \"\n }), _jsx(_components.span, {\n style: {\n color: \"#0A3069\",\n \"--shiki-dark\": \"#CE9178\"\n },\n children: \"\\\"eq\\\"\"\n }), _jsx(_components.span, {\n style: {\n color: \"#1F2328\",\n \"--shiki-dark\": \"#D4D4D4\"\n },\n children: \", \"\n }), _jsx(_components.span, {\n style: {\n color: \"#116329\",\n \"--shiki-dark\": \"#9CDCFE\"\n },\n children: \"\\\"value\\\"\"\n }), _jsx(_components.span, {\n style: {\n color: \"#1F2328\",\n \"--shiki-dark\": \"#D4D4D4\"\n },\n children: \": \"\n }), _jsx(_components.span, {\n style: {\n color: \"#0A3069\",\n \"--shiki-dark\": \"#CE9178\"\n },\n children: \"\\\"Sweden\\\"\"\n }), _jsx(_components.span, {\n style: {\n color: \"#1F2328\",\n \"--shiki-dark\": \"#D4D4D4\"\n },\n children: \"}\"\n })]\n }), \"\\n\", _jsx(_components.span, {\n className: \"line\",\n children: _jsx(_components.span, {\n style: {\n color: \"#1F2328\",\n \"--shiki-dark\": \"#D4D4D4\"\n },\n children: \" ]},\"\n })\n }), \"\\n\", _jsxs(_components.span, {\n className: \"line\",\n children: [_jsx(_components.span, {\n style: {\n color: \"#1F2328\",\n \"--shiki-dark\": \"#D4D4D4\"\n },\n children: \" {\"\n }), _jsx(_components.span, {\n style: {\n color: \"#116329\",\n \"--shiki-dark\": \"#9CDCFE\"\n },\n children: \"\\\"op\\\"\"\n }), _jsx(_components.span, {\n style: {\n color: \"#1F2328\",\n \"--shiki-dark\": \"#D4D4D4\"\n },\n children: \": \"\n }), _jsx(_components.span, {\n style: {\n color: \"#0A3069\",\n \"--shiki-dark\": \"#CE9178\"\n },\n children: \"\\\"and\\\"\"\n }), _jsx(_components.span, {\n style: {\n color: \"#1F2328\",\n \"--shiki-dark\": \"#D4D4D4\"\n },\n children: \", \"\n }), _jsx(_components.span, {\n style: {\n color: \"#116329\",\n \"--shiki-dark\": \"#9CDCFE\"\n },\n children: \"\\\"conditions\\\"\"\n }), _jsx(_components.span, {\n style: {\n color: \"#1F2328\",\n \"--shiki-dark\": \"#D4D4D4\"\n },\n children: \": [\"\n })]\n }), \"\\n\", _jsxs(_components.span, {\n className: \"line\",\n children: [_jsx(_components.span, {\n style: {\n color: \"#1F2328\",\n \"--shiki-dark\": \"#D4D4D4\"\n },\n children: \" {\"\n }), _jsx(_components.span, {\n style: {\n color: \"#116329\",\n \"--shiki-dark\": \"#9CDCFE\"\n },\n children: \"\\\"field\\\"\"\n }), _jsx(_components.span, {\n style: {\n color: \"#1F2328\",\n \"--shiki-dark\": \"#D4D4D4\"\n },\n children: \": {\"\n }), _jsx(_components.span, {\n style: {\n color: \"#116329\",\n \"--shiki-dark\": \"#9CDCFE\"\n },\n children: \"\\\"source\\\"\"\n }), _jsx(_components.span, {\n style: {\n color: \"#1F2328\",\n \"--shiki-dark\": \"#D4D4D4\"\n },\n children: \": \"\n }), _jsx(_components.span, {\n style: {\n color: \"#0A3069\",\n \"--shiki-dark\": \"#CE9178\"\n },\n children: \"\\\"demographic\\\"\"\n }), _jsx(_components.span, {\n style: {\n color: \"#1F2328\",\n \"--shiki-dark\": \"#D4D4D4\"\n },\n children: \", \"\n }), _jsx(_components.span, {\n style: {\n color: \"#116329\",\n \"--shiki-dark\": \"#9CDCFE\"\n },\n children: \"\\\"key\\\"\"\n }), _jsx(_components.span, {\n style: {\n color: \"#1F2328\",\n \"--shiki-dark\": \"#D4D4D4\"\n },\n children: \": \"\n }), _jsx(_components.span, {\n style: {\n color: \"#0A3069\",\n \"--shiki-dark\": \"#CE9178\"\n },\n children: \"\\\"occupation\\\"\"\n }), _jsx(_components.span, {\n style: {\n color: \"#1F2328\",\n \"--shiki-dark\": \"#D4D4D4\"\n },\n children: \"},\"\n })]\n }), \"\\n\", _jsxs(_components.span, {\n className: \"line\",\n children: [_jsx(_components.span, {\n style: {\n color: \"#116329\",\n \"--shiki-dark\": \"#9CDCFE\"\n },\n children: \" \\\"operator\\\"\"\n }), _jsx(_components.span, {\n style: {\n color: \"#1F2328\",\n \"--shiki-dark\": \"#D4D4D4\"\n },\n children: \": \"\n }), _jsx(_components.span, {\n style: {\n color: \"#0A3069\",\n \"--shiki-dark\": \"#CE9178\"\n },\n children: \"\\\"eq\\\"\"\n }), _jsx(_components.span, {\n style: {\n color: \"#1F2328\",\n \"--shiki-dark\": \"#D4D4D4\"\n },\n children: \", \"\n }), _jsx(_components.span, {\n style: {\n color: \"#116329\",\n \"--shiki-dark\": \"#9CDCFE\"\n },\n children: \"\\\"value\\\"\"\n }), _jsx(_components.span, {\n style: {\n color: \"#1F2328\",\n \"--shiki-dark\": \"#D4D4D4\"\n },\n children: \": \"\n }), _jsx(_components.span, {\n style: {\n color: \"#0A3069\",\n \"--shiki-dark\": \"#CE9178\"\n },\n children: \"\\\"teacher\\\"\"\n }), _jsx(_components.span, {\n style: {\n color: \"#1F2328\",\n \"--shiki-dark\": \"#D4D4D4\"\n },\n children: \"},\"\n })]\n }), \"\\n\", _jsxs(_components.span, {\n className: \"line\",\n children: [_jsx(_components.span, {\n style: {\n color: \"#1F2328\",\n \"--shiki-dark\": \"#D4D4D4\"\n },\n children: \" {\"\n }), _jsx(_components.span, {\n style: {\n color: \"#116329\",\n \"--shiki-dark\": \"#9CDCFE\"\n },\n children: \"\\\"field\\\"\"\n }), _jsx(_components.span, {\n style: {\n color: \"#1F2328\",\n \"--shiki-dark\": \"#D4D4D4\"\n },\n children: \": {\"\n }), _jsx(_components.span, {\n style: {\n color: \"#116329\",\n \"--shiki-dark\": \"#9CDCFE\"\n },\n children: \"\\\"source\\\"\"\n }), _jsx(_components.span, {\n style: {\n color: \"#1F2328\",\n \"--shiki-dark\": \"#D4D4D4\"\n },\n children: \": \"\n }), _jsx(_components.span, {\n style: {\n color: \"#0A3069\",\n \"--shiki-dark\": \"#CE9178\"\n },\n children: \"\\\"demographic\\\"\"\n }), _jsx(_components.span, {\n style: {\n color: \"#1F2328\",\n \"--shiki-dark\": \"#D4D4D4\"\n },\n children: \", \"\n }), _jsx(_components.span, {\n style: {\n color: \"#116329\",\n \"--shiki-dark\": \"#9CDCFE\"\n },\n children: \"\\\"key\\\"\"\n }), _jsx(_components.span, {\n style: {\n color: \"#1F2328\",\n \"--shiki-dark\": \"#D4D4D4\"\n },\n children: \": \"\n }), _jsx(_components.span, {\n style: {\n color: \"#0A3069\",\n \"--shiki-dark\": \"#CE9178\"\n },\n children: \"\\\"country\\\"\"\n }), _jsx(_components.span, {\n style: {\n color: \"#1F2328\",\n \"--shiki-dark\": \"#D4D4D4\"\n },\n children: \"},\"\n })]\n }), \"\\n\", _jsxs(_components.span, {\n className: \"line\",\n children: [_jsx(_components.span, {\n style: {\n color: \"#116329\",\n \"--shiki-dark\": \"#9CDCFE\"\n },\n children: \" \\\"operator\\\"\"\n }), _jsx(_components.span, {\n style: {\n color: \"#1F2328\",\n \"--shiki-dark\": \"#D4D4D4\"\n },\n children: \": \"\n }), _jsx(_components.span, {\n style: {\n color: \"#0A3069\",\n \"--shiki-dark\": \"#CE9178\"\n },\n children: \"\\\"eq\\\"\"\n }), _jsx(_components.span, {\n style: {\n color: \"#1F2328\",\n \"--shiki-dark\": \"#D4D4D4\"\n },\n children: \", \"\n }), _jsx(_components.span, {\n style: {\n color: \"#116329\",\n \"--shiki-dark\": \"#9CDCFE\"\n },\n children: \"\\\"value\\\"\"\n }), _jsx(_components.span, {\n style: {\n color: \"#1F2328\",\n \"--shiki-dark\": \"#D4D4D4\"\n },\n children: \": \"\n }), _jsx(_components.span, {\n style: {\n color: \"#0A3069\",\n \"--shiki-dark\": \"#CE9178\"\n },\n children: \"\\\"Norway\\\"\"\n }), _jsx(_components.span, {\n style: {\n color: \"#1F2328\",\n \"--shiki-dark\": \"#D4D4D4\"\n },\n children: \"}\"\n })]\n }), \"\\n\", _jsx(_components.span, {\n className: \"line\",\n children: _jsx(_components.span, {\n style: {\n color: \"#1F2328\",\n \"--shiki-dark\": \"#D4D4D4\"\n },\n children: \" ]}\"\n })\n }), \"\\n\", _jsx(_components.span, {\n className: \"line\",\n children: _jsx(_components.span, {\n style: {\n color: \"#1F2328\",\n \"--shiki-dark\": \"#D4D4D4\"\n },\n children: \" ]\"\n })\n }), \"\\n\", _jsx(_components.span, {\n className: \"line\",\n children: _jsx(_components.span, {\n style: {\n color: \"#1F2328\",\n \"--shiki-dark\": \"#D4D4D4\"\n },\n children: \" },\"\n })\n }), \"\\n\", _jsxs(_components.span, {\n className: \"line\",\n children: [_jsx(_components.span, {\n style: {\n color: \"#116329\",\n \"--shiki-dark\": \"#9CDCFE\"\n },\n children: \" \\\"pagination\\\"\"\n }), _jsx(_components.span, {\n style: {\n color: \"#1F2328\",\n \"--shiki-dark\": \"#D4D4D4\"\n },\n children: \": {\"\n }), _jsx(_components.span, {\n style: {\n color: \"#116329\",\n \"--shiki-dark\": \"#9CDCFE\"\n },\n children: \"\\\"limit\\\"\"\n }), _jsx(_components.span, {\n style: {\n color: \"#1F2328\",\n \"--shiki-dark\": \"#D4D4D4\"\n },\n children: \": \"\n }), _jsx(_components.span, {\n style: {\n color: \"#0550AE\",\n \"--shiki-dark\": \"#B5CEA8\"\n },\n children: \"25\"\n }), _jsx(_components.span, {\n style: {\n color: \"#1F2328\",\n \"--shiki-dark\": \"#D4D4D4\"\n },\n children: \"}\"\n })]\n }), \"\\n\", _jsx(_components.span, {\n className: \"line\",\n children: _jsx(_components.span, {\n style: {\n color: \"#1F2328\",\n \"--shiki-dark\": \"#D4D4D4\"\n },\n children: \"}\"\n })\n }), \"\\n\"]\n })\n })\n }), \"\\n\", _jsx(_components.h2, {\n children: \"Testing whether an attribute is set\"\n }), \"\\n\", _jsxs(_components.p, {\n children: [_jsx(_components.code, {\n children: \"is_not_null\"\n }), \" matches people who have a value for an attribute, and\\n\", _jsx(_components.code, {\n children: \"is_null\"\n }), \" matches people who do not. Reach for these rather than comparing\\nagainst an empty string: an attribute nobody filled in holds no value at\\nall, and it satisfies no ordinary comparison, not even a negated one.\"]\n }), \"\\n\", _jsx(_components.h2, {\n children: \"Limits, and how a rule is refused\"\n }), \"\\n\", _jsxs(_components.p, {\n children: [\"A rule may nest groups at most \", _jsx(_components.strong, {\n children: \"2\"\n }), \" levels deep, hold at most \", _jsx(_components.strong, {\n children: \"15\"\n }), \"\\nconditions in any one group, and \", _jsx(_components.strong, {\n children: \"25\"\n }), \" in total.\"]\n }), \"\\n\", _jsxs(_components.p, {\n children: [\"Both refusals are a \", _jsx(_components.code, {\n children: \"422\"\n }), \" carrying an \", _jsx(_components.code, {\n children: \"error_kind\"\n }), \", and they have different\\nfixes:\"]\n }), \"\\n\", _jsxs(_components.ul, {\n children: [\"\\n\", _jsxs(_components.li, {\n children: [_jsx(_components.code, {\n children: \"search_rule_too_complex\"\n }), \": past one of those caps. The detail names the\\noffending count and the limit. Combining values with \", _jsx(_components.code, {\n children: \"in\"\n }), \" costs one\\ncondition instead of one per value, and is the usual fix.\"]\n }), \"\\n\", _jsxs(_components.li, {\n children: [_jsx(_components.code, {\n children: \"search_rule_invalid\"\n }), \": the tree is malformed, or it names an attribute,\\nsource or operator this API does not publish. The detail names the\\noffender, and \", _jsx(_components.code, {\n children: \"GET .../people/schema\"\n }), \" is the vocabulary it was checked\\nagainst.\"]\n }), \"\\n\"]\n }), \"\\n\", _jsxs(_components.p, {\n children: [\"A malformed request BODY (rather than a bad rule) is the ordinary\\nvalidation \", _jsx(_components.code, {\n children: \"422\"\n }), \" with the field-level envelope, which is why this\\noperation’s \", _jsx(_components.code, {\n children: \"422\"\n }), \" documents either shape.\"]\n }), \"\\n\", _jsx(_components.h2, {\n children: \"Saved segments\"\n }), \"\\n\", _jsxs(_components.p, {\n children: [\"Segments live in the ish app and are not exposed here. A segment IS a rule,\\nso the way to use one is to send its rule as the \", _jsx(_components.code, {\n children: \"rule\"\n }), \" on this request:\\nthat is how the ish console itself applies them.\"]\n })]\n });\n}\nfunction MDXContent(props = {}) {\n const {wrapper: MDXLayout} = {\n ..._provideComponents(),\n ...props.components\n };\n return MDXLayout ? _jsx(MDXLayout, {\n ...props,\n children: _jsx(_createMdxContent, {\n ...props\n })\n }) : _createMdxContent(props);\n}\nreturn {\n default: MDXContent\n};\nfunction _missingMdxReference(id, component) {\n throw new Error(\"Expected \" + (component ? \"component\" : \"object\") + \" `\" + id + \"` to be defined: you likely forgot to import, pass, or provide it.\");\n}\n","frontmatter":{},"scope":{}},"pageType":"default","mdx":{"mdxSource":{"compiledSource":"\"use strict\";const{Fragment:_Fragment,jsx:_jsx}=arguments[0];const{useMDXComponents:_provideComponents}=arguments[0];function _createMdxContent(props){return _jsx(_Fragment,{})}function MDXContent(props={}){const{wrapper:MDXLayout}={..._provideComponents(),...props.components};return MDXLayout?_jsx(MDXLayout,{...props,children:_jsx(_createMdxContent,{...props})}):_createMdxContent(props)}return{default:MDXContent}","frontmatter":{},"scope":{"config":{},"pageMetadata":{"title":"Search People","description":"Find people by their attributes, using a boolean rule tree.\n\nSearches the same pool the list endpoint serves (your workspace's people\nplus the platform library), and returns the same paginated envelope.\n\n## The rule tree\n\nA rule is a single node. A node is either a **leaf** or a **group**, never\nboth:\n\n- A **leaf** tests one attribute: `{\"field\": {\"source\": ..., \"key\": ...},\n \"operator\": ..., \"value\": ...}`. Copy `source` and `key` from the\n attribute's `filter` block in `GET .../people/schema`; that endpoint is\n the authoritative vocabulary, and an attribute or operator it does not\n list is refused with a `422` rather than matching nothing.\n- A **group** combines nodes: `{\"op\": \"and\" | \"or\" | \"not\", \"conditions\":\n [...]}`.\n\n## Boolean semantics, exactly\n\nA group's `op` applies to its OWN `conditions` and to nothing else. `and`\nmatches a person satisfying **every** condition in that group; `or` matches\na person satisfying **at least one**; `not` takes **exactly one** condition\nand matches people who do not satisfy it. Groups nest, so a group inside\nanother group is evaluated on its own first and its result is then one\ninput to the parent's operator. There is no precedence to remember and no\nimplicit combination anywhere: two conditions are only ever joined by the\n`op` of the group holding them.\n\n## A worked example\n\n\"Nurses in Sweden, plus teachers in Norway\" is two AND-groups joined by an\nOR. Note that the country is repeated in both groups: the outer `or` does\nnot distribute over anything, so a condition placed outside the groups\nwould not apply to either.\n\n```json\n{\n \"rule\": {\n \"op\": \"or\",\n \"conditions\": [\n {\"op\": \"and\", \"conditions\": [\n {\"field\": {\"source\": \"demographic\", \"key\": \"occupation\"},\n \"operator\": \"eq\", \"value\": \"nurse\"},\n {\"field\": {\"source\": \"demographic\", \"key\": \"country\"},\n \"operator\": \"eq\", \"value\": \"Sweden\"}\n ]},\n {\"op\": \"and\", \"conditions\": [\n {\"field\": {\"source\": \"demographic\", \"key\": \"occupation\"},\n \"operator\": \"eq\", \"value\": \"teacher\"},\n {\"field\": {\"source\": \"demographic\", \"key\": \"country\"},\n \"operator\": \"eq\", \"value\": \"Norway\"}\n ]}\n ]\n },\n \"pagination\": {\"limit\": 25}\n}\n```\n\n## Testing whether an attribute is set\n\n`is_not_null` matches people who have a value for an attribute, and\n`is_null` matches people who do not. Reach for these rather than comparing\nagainst an empty string: an attribute nobody filled in holds no value at\nall, and it satisfies no ordinary comparison, not even a negated one.\n\n## Limits, and how a rule is refused\n\nA rule may nest groups at most **2** levels deep, hold at most **15**\nconditions in any one group, and **25** in total.\n\nBoth refusals are a `422` carrying an `error_kind`, and they have different\nfixes:\n\n- `search_rule_too_complex`: past one of those caps. The detail names the\n offending count and the limit. Combining values with `in` costs one\n condition instead of one per value, and is the usual fix.\n- `search_rule_invalid`: the tree is malformed, or it names an attribute,\n source or operator this API does not publish. The detail names the\n offender, and `GET .../people/schema` is the vocabulary it was checked\n against.\n\nA malformed request BODY (rather than a bad rule) is the ordinary\nvalidation `422` with the field-level envelope, which is why this\noperation's `422` documents either shape.\n\n## Saved segments\n\nSegments live in the ish app and are not exposed here. A segment IS a rule,\nso the way to use one is to send its rule as the `rule` on this request:\nthat is how the ish console itself applies them.","deprecated":null,"version":null,"openapi":"/api/openapi.public.json post /api/v1/workspaces/{workspace_id}/people/search","href":"/api/reference/people/search-people","autogeneratedByOpenApi":true}}},"mdxSourceWithNoJs":null},"mdxExtracts":{"tableOfContents":[],"codeExamples":{}},"jsLinks":[],"openApiReferenceData":{"operation":{"description":"Find people by their attributes, using a boolean rule tree.\n\nSearches the same pool the list endpoint serves (your workspace's people\nplus the platform library), and returns the same paginated envelope.\n\n## The rule tree\n\nA rule is a single node. A node is either a **leaf** or a **group**, never\nboth:\n\n- A **leaf** tests one attribute: `{\"field\": {\"source\": ..., \"key\": ...},\n \"operator\": ..., \"value\": ...}`. Copy `source` and `key` from the\n attribute's `filter` block in `GET .../people/schema`; that endpoint is\n the authoritative vocabulary, and an attribute or operator it does not\n list is refused with a `422` rather than matching nothing.\n- A **group** combines nodes: `{\"op\": \"and\" | \"or\" | \"not\", \"conditions\":\n [...]}`.\n\n## Boolean semantics, exactly\n\nA group's `op` applies to its OWN `conditions` and to nothing else. `and`\nmatches a person satisfying **every** condition in that group; `or` matches\na person satisfying **at least one**; `not` takes **exactly one** condition\nand matches people who do not satisfy it. Groups nest, so a group inside\nanother group is evaluated on its own first and its result is then one\ninput to the parent's operator. There is no precedence to remember and no\nimplicit combination anywhere: two conditions are only ever joined by the\n`op` of the group holding them.\n\n## A worked example\n\n\"Nurses in Sweden, plus teachers in Norway\" is two AND-groups joined by an\nOR. Note that the country is repeated in both groups: the outer `or` does\nnot distribute over anything, so a condition placed outside the groups\nwould not apply to either.\n\n```json\n{\n \"rule\": {\n \"op\": \"or\",\n \"conditions\": [\n {\"op\": \"and\", \"conditions\": [\n {\"field\": {\"source\": \"demographic\", \"key\": \"occupation\"},\n \"operator\": \"eq\", \"value\": \"nurse\"},\n {\"field\": {\"source\": \"demographic\", \"key\": \"country\"},\n \"operator\": \"eq\", \"value\": \"Sweden\"}\n ]},\n {\"op\": \"and\", \"conditions\": [\n {\"field\": {\"source\": \"demographic\", \"key\": \"occupation\"},\n \"operator\": \"eq\", \"value\": \"teacher\"},\n {\"field\": {\"source\": \"demographic\", \"key\": \"country\"},\n \"operator\": \"eq\", \"value\": \"Norway\"}\n ]}\n ]\n },\n \"pagination\": {\"limit\": 25}\n}\n```\n\n## Testing whether an attribute is set\n\n`is_not_null` matches people who have a value for an attribute, and\n`is_null` matches people who do not. Reach for these rather than comparing\nagainst an empty string: an attribute nobody filled in holds no value at\nall, and it satisfies no ordinary comparison, not even a negated one.\n\n## Limits, and how a rule is refused\n\nA rule may nest groups at most **2** levels deep, hold at most **15**\nconditions in any one group, and **25** in total.\n\nBoth refusals are a `422` carrying an `error_kind`, and they have different\nfixes:\n\n- `search_rule_too_complex`: past one of those caps. The detail names the\n offending count and the limit. Combining values with `in` costs one\n condition instead of one per value, and is the usual fix.\n- `search_rule_invalid`: the tree is malformed, or it names an attribute,\n source or operator this API does not publish. The detail names the\n offender, and `GET .../people/schema` is the vocabulary it was checked\n against.\n\nA malformed request BODY (rather than a bad rule) is the ordinary\nvalidation `422` with the field-level envelope, which is why this\noperation's `422` documents either shape.\n\n## Saved segments\n\nSegments live in the ish app and are not exposed here. A segment IS a rule,\nso the way to use one is to send its rule as the `rule` on this request:\nthat is how the ish console itself applies them.","operationId":"searchPeople","parameters":["dc830b6e-39c3-4169-82b9-99ca87659bcf"],"requestBody":"43dd82ea-12da-4c84-988b-bbb995155b8e","responses":{"200":"4e32c415-8e67-458f-82ae-1504f4f68e13","401":"59549a97-8d2e-43cc-b578-e21c2faf897f","403":"72c49585-f4e2-4f8d-a2e7-693821e69aae","404":"5d982ca9-f14c-467c-9c50-4894c80b472b","422":"d038422d-397f-4332-ad6d-bd328acba2b0","429":"34bc82e2-8014-4387-8604-b429444b2b1f"},"security":["f946cc05-85e3-4aaa-a739-c076c4a05a30"],"summary":"Search People","tags":["people"],"method":"post","type":"path","servers":["22c3a961-b6d9-4922-b5aa-d0aac292aa39"],"path":"/api/v1/workspaces/{workspace_id}/people/search","baseUrlOptions":["https://api.ishlabs.io"],"title":"Search People","codeSamples":[],"requiredOnlyExamples":false,"requestExampleType":"generated","responseExampleType":"generated"},"dependencies":{"parameters":{"dc830b6e-39c3-4169-82b9-99ca87659bcf":{"in":"path","name":"workspace_id","required":true,"schema":{"format":"uuid","title":"Workspace Id","type":"string","isRequired":true,"uniqueKey":"","typeLabel":"string\u003cuuid>"}}},"requestBody":{"content":{"application/json":{"schema":{"additionalProperties":false,"description":"A capped rule-tree query over the workspace's reachable people.\n\nUnknown keys are rejected rather than ignored: a typo in a filter that\nsilently widened the result set would be indistinguishable from a match.","properties":{"archived":{"default":false,"description":"`false` (the default) searches live people; `true` searches the archive instead. The two sets are disjoint, so this selects which one you are searching rather than widening the search.","title":"Archived","type":"boolean","uniqueKey":"archived","typeLabel":"boolean"},"generation_job_id":{"oneOf":[{"type":"string","title":"Generation Job Id","description":"Restrict to the people one generation job produced. Reads its own writes: a person is visible here the moment the job records them.","format":"uuid","uniqueKey":"generation_job_id.oneOf.0","typeLabel":"string\u003cuuid>"},{"type":"null","title":"Generation Job Id","description":"Restrict to the people one generation job produced. Reads its own writes: a person is visible here the moment the job records them.","uniqueKey":"generation_job_id.oneOf.1","typeLabel":"null"}],"uniqueKey":"generation_job_id","typeLabel":"string\u003cuuid> | null"},"owner":{"oneOf":[{"type":"string","title":"Owner","description":"Restrict to one owner. Omitted returns both, which is the set you can open a session for.","enum":["self","platform"],"uniqueKey":"owner.oneOf.0","typeLabel":"enum\u003cstring>"},{"type":"null","title":"Owner","description":"Restrict to one owner. Omitted returns both, which is the set you can open a session for.","uniqueKey":"owner.oneOf.1","typeLabel":"null"}],"uniqueKey":"owner","typeLabel":"enum\u003cstring> | null"},"pagination":{"additionalProperties":false,"description":"Keyset pagination, in the body because the query is.","properties":{"after":{"oneOf":[{"type":"string","title":"After","description":"Opaque cursor from a prior page's `next_cursor`.","uniqueKey":"pagination.after.oneOf.0","typeLabel":"string"},{"type":"null","title":"After","description":"Opaque cursor from a prior page's `next_cursor`.","uniqueKey":"pagination.after.oneOf.1","typeLabel":"null"}],"uniqueKey":"pagination.after","typeLabel":"string | null"},"limit":{"default":25,"maximum":100,"minimum":1,"title":"Limit","type":"integer","uniqueKey":"pagination.limit","typeLabel":"integer"}},"title":"PublicPersonSearchPagination","type":"object","uniqueKey":"pagination","typeLabel":"PublicPersonSearchPagination · object"},"rule":{"oneOf":[{"type":"object","title":"Rule","description":"A boolean tree of filters. See the endpoint description for the grammar, the caps, and a worked example.","additionalProperties":true,"uniqueKey":"rule.oneOf.0","typeLabel":"Rule · object"},{"type":"null","title":"Rule","description":"A boolean tree of filters. See the endpoint description for the grammar, the caps, and a worked example.","uniqueKey":"rule.oneOf.1","typeLabel":"null"}],"uniqueKey":"rule","typeLabel":"Rule · object | null"},"search":{"oneOf":[{"type":"string","title":"Search","description":"Case-insensitive substring match on the person's name.","maxLength":200,"uniqueKey":"search.oneOf.0","typeLabel":"string"},{"type":"null","title":"Search","description":"Case-insensitive substring match on the person's name.","uniqueKey":"search.oneOf.1","typeLabel":"null"}],"uniqueKey":"search","typeLabel":"string | null"}},"title":"PublicPersonSearchRequest","type":"object","uniqueKey":"","typeLabel":"PublicPersonSearchRequest · object"},"examples":{"Example":{"title":"Example","value":{"archived":false,"generation_job_id":"3c90c3cc-0d44-4b50-8888-8dd25736052a","pagination":{"after":"\u003cstring>","limit":25},"rule":{},"search":"\u003cstring>"}}},"exampleType":"generated"}},"required":true,"exampleType":"generated"},"responses":{"4e32c415-8e67-458f-82ae-1504f4f68e13":{"content":{"application/json":{"schema":{"description":"A keyset-paginated page of people.\n\nOrdered `created_at DESC, id DESC`, the same order and the same envelope\nas the session list, so one pagination helper in an SDK drives both.","properties":{"has_more":{"description":"True when more people exist beyond this page.","title":"Has More","type":"boolean","isRequired":true,"uniqueKey":"has_more","typeLabel":"boolean"},"items":{"items":{"description":"One person, as an external integrator sees them.\n\nThe field list is CLOSED and hand-maintained. It carries who the person is\n(identity + demographics + interests) and nothing about how ish came to\nhold that row: no moderation verdict, no publisher, no viewer-specific\nstate, no internal config pointer, no custom fields.","properties":{"created_at":{"format":"date-time","title":"Created At","type":"string","isRequired":true,"uniqueKey":"\\items.items.[INDEX].created_at","typeLabel":"string\u003cdate-time>"},"id":{"format":"uuid","title":"Id","type":"string","isRequired":true,"uniqueKey":"\\items.items.[INDEX].id","typeLabel":"string\u003cuuid>"},"name":{"description":"The person's display name.","title":"Name","type":"string","isRequired":true,"uniqueKey":"\\items.items.[INDEX].name","typeLabel":"string"},"owner":{"description":"`self` for a person your workspace owns; `platform` for one published in the shared ish library. Both are usable in a session; only `self` rows are yours to edit.","enum":["self","platform"],"title":"Owner","type":"string","isRequired":true,"uniqueKey":"\\items.items.[INDEX].owner","typeLabel":"enum\u003cstring>"},"updated_at":{"format":"date-time","title":"Updated At","type":"string","isRequired":true,"uniqueKey":"\\items.items.[INDEX].updated_at","typeLabel":"string\u003cdate-time>"},"accessibility_profile":{"oneOf":[{"type":"object","title":"Accessibility Profile","description":"Declared accessibility needs, as a nested object of boolean and enum flags. Only non-default keys are present. An open union: new keys appear over time.","additionalProperties":true,"uniqueKey":"\\items.items.[INDEX].accessibility_profile.oneOf.0","typeLabel":"Accessibility Profile · object"},{"type":"null","title":"Accessibility Profile","description":"Declared accessibility needs, as a nested object of boolean and enum flags. Only non-default keys are present. An open union: new keys appear over time.","uniqueKey":"\\items.items.[INDEX].accessibility_profile.oneOf.1","typeLabel":"null"}],"uniqueKey":"\\items.items.[INDEX].accessibility_profile","typeLabel":"Accessibility Profile · object | null"},"archived_at":{"oneOf":[{"type":"string","title":"Archived At","description":"When this person was archived, or null while they are live. An archived person is hidden from the default listing and closed to edits, but stays readable by id and keeps every session that ran for them intact. `POST .../restore` clears it.","format":"date-time","uniqueKey":"\\items.items.[INDEX].archived_at.oneOf.0","typeLabel":"string\u003cdate-time>"},{"type":"null","title":"Archived At","description":"When this person was archived, or null while they are live. An archived person is hidden from the default listing and closed to edits, but stays readable by id and keeps every session that ran for them intact. `POST .../restore` clears it.","uniqueKey":"\\items.items.[INDEX].archived_at.oneOf.1","typeLabel":"null"}],"uniqueKey":"\\items.items.[INDEX].archived_at","typeLabel":"string\u003cdate-time> | null"},"avatar_url":{"oneOf":[{"type":"string","title":"Avatar Url","description":"Publicly fetchable avatar image, when one exists.","uniqueKey":"\\items.items.[INDEX].avatar_url.oneOf.0","typeLabel":"string"},{"type":"null","title":"Avatar Url","description":"Publicly fetchable avatar image, when one exists.","uniqueKey":"\\items.items.[INDEX].avatar_url.oneOf.1","typeLabel":"null"}],"uniqueKey":"\\items.items.[INDEX].avatar_url","typeLabel":"string | null"},"bio":{"oneOf":[{"type":"string","title":"Bio","description":"Free-text background in the person's own register. This is the bulk of what the model is told about them when a session runs.","uniqueKey":"\\items.items.[INDEX].bio.oneOf.0","typeLabel":"string"},{"type":"null","title":"Bio","description":"Free-text background in the person's own register. This is the bulk of what the model is told about them when a session runs.","uniqueKey":"\\items.items.[INDEX].bio.oneOf.1","typeLabel":"null"}],"uniqueKey":"\\items.items.[INDEX].bio","typeLabel":"string | null"},"city":{"oneOf":[{"type":"string","title":"City","uniqueKey":"\\items.items.[INDEX].city.oneOf.0","typeLabel":"string"},{"type":"null","title":"City","uniqueKey":"\\items.items.[INDEX].city.oneOf.1","typeLabel":"null"}],"uniqueKey":"\\items.items.[INDEX].city","typeLabel":"string | null"},"country":{"oneOf":[{"type":"string","title":"Country","uniqueKey":"\\items.items.[INDEX].country.oneOf.0","typeLabel":"string"},{"type":"null","title":"Country","uniqueKey":"\\items.items.[INDEX].country.oneOf.1","typeLabel":"null"}],"uniqueKey":"\\items.items.[INDEX].country","typeLabel":"string | null"},"date_of_birth":{"oneOf":[{"type":"string","title":"Date Of Birth","format":"date","uniqueKey":"\\items.items.[INDEX].date_of_birth.oneOf.0","typeLabel":"string\u003cdate>"},{"type":"null","title":"Date Of Birth","uniqueKey":"\\items.items.[INDEX].date_of_birth.oneOf.1","typeLabel":"null"}],"uniqueKey":"\\items.items.[INDEX].date_of_birth","typeLabel":"string\u003cdate> | null"},"education_level":{"oneOf":[{"type":"string","title":"EducationLevel","enum":["less_than_secondary","secondary","some_post_secondary","vocational_or_associate","bachelor","graduate"],"uniqueKey":"\\items.items.[INDEX].education_level.oneOf.0","typeLabel":"enum\u003cstring>"},{"type":"null","uniqueKey":"\\items.items.[INDEX].education_level.oneOf.1","typeLabel":"null"}],"uniqueKey":"\\items.items.[INDEX].education_level","typeLabel":"enum\u003cstring> | null"},"employment_status":{"oneOf":[{"type":"string","title":"EmploymentStatus","enum":["employed_full_time","employed_part_time","self_employed","unemployed_seeking","student","homemaker","retired","unable_to_work","other"],"uniqueKey":"\\items.items.[INDEX].employment_status.oneOf.0","typeLabel":"enum\u003cstring>"},{"type":"null","uniqueKey":"\\items.items.[INDEX].employment_status.oneOf.1","typeLabel":"null"}],"uniqueKey":"\\items.items.[INDEX].employment_status","typeLabel":"enum\u003cstring> | null"},"external_id":{"oneOf":[{"type":"string","title":"External Id","description":"Your own identifier for this person, if you set one. Unique among the people your workspace owns. Always null on a `platform` person: the shared library is nobody's to label.","uniqueKey":"\\items.items.[INDEX].external_id.oneOf.0","typeLabel":"string"},{"type":"null","title":"External Id","description":"Your own identifier for this person, if you set one. Unique among the people your workspace owns. Always null on a `platform` person: the shared library is nobody's to label.","uniqueKey":"\\items.items.[INDEX].external_id.oneOf.1","typeLabel":"null"}],"uniqueKey":"\\items.items.[INDEX].external_id","typeLabel":"string | null"},"gender":{"oneOf":[{"type":"string","title":"Gender","description":"Gender options for people.","enum":["male","female","non-binary","prefer_not_to_say"],"uniqueKey":"\\items.items.[INDEX].gender.oneOf.0","typeLabel":"enum\u003cstring>"},{"type":"null","uniqueKey":"\\items.items.[INDEX].gender.oneOf.1","typeLabel":"null"}],"uniqueKey":"\\items.items.[INDEX].gender","typeLabel":"enum\u003cstring> | null"},"generation_job_id":{"oneOf":[{"type":"string","title":"Generation Job Id","description":"The generation job that produced this person, when one did. This is how you collect a job's results: list people filtered by it.","format":"uuid","uniqueKey":"\\items.items.[INDEX].generation_job_id.oneOf.0","typeLabel":"string\u003cuuid>"},{"type":"null","title":"Generation Job Id","description":"The generation job that produced this person, when one did. This is how you collect a job's results: list people filtered by it.","uniqueKey":"\\items.items.[INDEX].generation_job_id.oneOf.1","typeLabel":"null"}],"uniqueKey":"\\items.items.[INDEX].generation_job_id","typeLabel":"string\u003cuuid> | null"},"household":{"oneOf":[{"type":"string","title":"Household","enum":["single","couple_no_kids","couple_with_kids","single_parent","shared_housing","adult_with_parents","multi_generational"],"uniqueKey":"\\items.items.[INDEX].household.oneOf.0","typeLabel":"enum\u003cstring>"},{"type":"null","uniqueKey":"\\items.items.[INDEX].household.oneOf.1","typeLabel":"null"}],"uniqueKey":"\\items.items.[INDEX].household","typeLabel":"enum\u003cstring> | null"},"income_level":{"oneOf":[{"type":"string","title":"IncomeLevel","enum":["lower","lower_middle","middle","upper_middle","upper","prefer_not_to_say"],"uniqueKey":"\\items.items.[INDEX].income_level.oneOf.0","typeLabel":"enum\u003cstring>"},{"type":"null","uniqueKey":"\\items.items.[INDEX].income_level.oneOf.1","typeLabel":"null"}],"uniqueKey":"\\items.items.[INDEX].income_level","typeLabel":"enum\u003cstring> | null"},"interests":{"description":"IAB taxonomy node ids this person is tagged with. Filterable via the `qualification` rule source, where a parent node also matches everyone tagged at a node beneath it.","items":{"type":"string","uniqueKey":"\\items.items.[INDEX].interests.items.[INDEX]","typeLabel":"string"},"title":"Interests","type":"array","uniqueKey":"\\items.items.[INDEX].interests","typeLabel":"string[]"},"locale_type":{"oneOf":[{"type":"string","title":"LocaleType","enum":["urban","suburban","small_town","rural"],"uniqueKey":"\\items.items.[INDEX].locale_type.oneOf.0","typeLabel":"enum\u003cstring>"},{"type":"null","uniqueKey":"\\items.items.[INDEX].locale_type.oneOf.1","typeLabel":"null"}],"uniqueKey":"\\items.items.[INDEX].locale_type","typeLabel":"enum\u003cstring> | null"},"occupation":{"oneOf":[{"type":"string","title":"Occupation","description":"Free-text job title, as written on the person.","uniqueKey":"\\items.items.[INDEX].occupation.oneOf.0","typeLabel":"string"},{"type":"null","title":"Occupation","description":"Free-text job title, as written on the person.","uniqueKey":"\\items.items.[INDEX].occupation.oneOf.1","typeLabel":"null"}],"uniqueKey":"\\items.items.[INDEX].occupation","typeLabel":"string | null"},"occupation_code":{"oneOf":[{"type":"string","title":"Occupation Code","description":"Canonical ESCO/ISCO code beside the free-text `occupation`. Codes are hierarchical, so a `starts_with` filter on a group prefix selects a whole occupational family.","uniqueKey":"\\items.items.[INDEX].occupation_code.oneOf.0","typeLabel":"string"},{"type":"null","title":"Occupation Code","description":"Canonical ESCO/ISCO code beside the free-text `occupation`. Codes are hierarchical, so a `starts_with` filter on a group prefix selects a whole occupational family.","uniqueKey":"\\items.items.[INDEX].occupation_code.oneOf.1","typeLabel":"null"}],"uniqueKey":"\\items.items.[INDEX].occupation_code","typeLabel":"string | null"},"type":{"const":"ai","default":"ai","description":"Always `ai` on this API. ish also models real people who have consented to participate, and they are never readable here or through any credential you can mint. Treat this as an open union and tolerate a value you do not recognize.","title":"Type","type":"string","uniqueKey":"\\items.items.[INDEX].type","typeLabel":"string"},"workspace_id":{"oneOf":[{"type":"string","title":"Workspace Id","description":"The owning workspace, present only when `owner` is `self`. A `platform` person belongs to no workspace, so this is null rather than naming one.","format":"uuid","uniqueKey":"\\items.items.[INDEX].workspace_id.oneOf.0","typeLabel":"string\u003cuuid>"},{"type":"null","title":"Workspace Id","description":"The owning workspace, present only when `owner` is `self`. A `platform` person belongs to no workspace, so this is null rather than naming one.","uniqueKey":"\\items.items.[INDEX].workspace_id.oneOf.1","typeLabel":"null"}],"uniqueKey":"\\items.items.[INDEX].workspace_id","typeLabel":"string\u003cuuid> | null"}},"required":["id","name","owner","created_at","updated_at"],"title":"PublicPersonResponse","type":"object","uniqueKey":"\\items.items.[INDEX]","typeLabel":"PublicPersonResponse · object"},"title":"Items","type":"array","isRequired":true,"uniqueKey":"\\items","typeLabel":"PublicPersonResponse · object[]"},"next_cursor":{"oneOf":[{"type":"string","title":"Next Cursor","description":"Opaque keyset cursor for the next page (pass as `after`); null on the final page.","isRequired":true,"uniqueKey":"next_cursor.oneOf.0","typeLabel":"string"},{"type":"null","title":"Next Cursor","description":"Opaque keyset cursor for the next page (pass as `after`); null on the final page.","isRequired":true,"uniqueKey":"next_cursor.oneOf.1","typeLabel":"null"}],"isRequired":true,"uniqueKey":"next_cursor","typeLabel":"string | null"}},"required":["items","has_more","next_cursor"],"title":"PublicPersonListResponse","type":"object","uniqueKey":"","typeLabel":"PublicPersonListResponse · object"},"examples":{"Example":{"title":"Example","value":{"has_more":true,"items":[{"created_at":"2023-11-07T05:31:56Z","id":"3c90c3cc-0d44-4b50-8888-8dd25736052a","name":"\u003cstring>","owner":"self","updated_at":"2023-11-07T05:31:56Z","accessibility_profile":{},"archived_at":"2023-11-07T05:31:56Z","avatar_url":"\u003cstring>","bio":"\u003cstring>","city":"\u003cstring>","country":"\u003cstring>","date_of_birth":"2023-12-25","education_level":"less_than_secondary","employment_status":"employed_full_time","external_id":"\u003cstring>","gender":"male","generation_job_id":"3c90c3cc-0d44-4b50-8888-8dd25736052a","household":"single","income_level":"lower","interests":["\u003cstring>"],"locale_type":"urban","occupation":"\u003cstring>","occupation_code":"\u003cstring>","type":"ai","workspace_id":"3c90c3cc-0d44-4b50-8888-8dd25736052a"}],"next_cursor":"\u003cstring>"}}},"exampleType":"generated"}},"description":"Successful Response","headers":{"X-Request-Id":{"description":"Per-response correlation id, present on EVERY response (success and error). Error bodies echo it as `request_id`.","schema":{"type":"string"}},"x-ratelimit-limit":{"description":"Ceiling for the rate-limit window this request charged. Present on responses made with an API key against a rate-limited operation, including the `429` itself; absent for user access tokens (which carry no per-key budget) and when the rate-limit backend could not be read.","schema":{"type":"integer"}},"x-ratelimit-remaining":{"description":"Requests left in that window AFTER this one was counted. Pace off this rather than waiting for a `429`.","schema":{"type":"integer"}},"x-ratelimit-reset":{"description":"**Seconds from now** until that window resets (a delta, NOT a Unix timestamp). Measured when the response is written. Omitted on the rare occasion the reset instant could not be read, while `limit` and `remaining` are still published.","schema":{"type":"integer"}}},"exampleType":"generated"},"59549a97-8d2e-43cc-b578-e21c2faf897f":{"content":{"application/json":{"schema":{"description":"Generic error envelope for 4xx/5xx responses other than request-shape validation.","properties":{"detail":{"oneOf":[{"type":"string","title":"Detail","description":"A human-readable message, OR a structured object carrying a machine-readable `error_kind` (e.g. `idempotency_conflict`, `turn_index_mismatch`, `decision_invalid`).","isRequired":true,"uniqueKey":"detail.oneOf.0","typeLabel":"string"},{"type":"object","title":"Detail","description":"A human-readable message, OR a structured object carrying a machine-readable `error_kind` (e.g. `idempotency_conflict`, `turn_index_mismatch`, `decision_invalid`).","additionalProperties":true,"isRequired":true,"uniqueKey":"detail.oneOf.1","typeLabel":"Detail · object"}],"isRequired":true,"uniqueKey":"detail","typeLabel":"string | Detail · object"},"request_id":{"description":"Correlation id; identical to the `X-Request-Id` response header. Quote it in support requests.","title":"Request Id","type":"string","isRequired":true,"uniqueKey":"request_id","typeLabel":"string"},"docs_url":{"description":"Link to this error's entry in the error catalog. Present whenever `detail` carries a registered `error_kind`; absent on unclassified errors.","title":"Docs Url","type":"string","uniqueKey":"docs_url","typeLabel":"string"}},"required":["detail","request_id"],"title":"Error","type":"object","uniqueKey":"","typeLabel":"Error · object"},"examples":{"Example":{"title":"Example","value":{"detail":"\u003cstring>","request_id":"\u003cstring>","docs_url":"\u003cstring>"}}},"exampleType":"generated"}},"description":"The bearer token is missing, malformed, unknown, or revoked (`detail.error_kind = 'invalid_api_key'`). One kind covers all four deliberately: distinguishing them would confirm which guesses are real keys.","headers":{"X-Request-Id":{"description":"Per-response correlation id, present on EVERY response (success and error). Error bodies echo it as `request_id`.","schema":{"type":"string"}},"x-ratelimit-limit":{"description":"Ceiling for the rate-limit window this request charged. Present on responses made with an API key against a rate-limited operation, including the `429` itself; absent for user access tokens (which carry no per-key budget) and when the rate-limit backend could not be read.","schema":{"type":"integer"}},"x-ratelimit-remaining":{"description":"Requests left in that window AFTER this one was counted. Pace off this rather than waiting for a `429`.","schema":{"type":"integer"}},"x-ratelimit-reset":{"description":"**Seconds from now** until that window resets (a delta, NOT a Unix timestamp). Measured when the response is written. Omitted on the rare occasion the reset instant could not be read, while `limit` and `remaining` are still published.","schema":{"type":"integer"}}},"exampleType":"generated"},"72c49585-f4e2-4f8d-a2e7-693821e69aae":{"content":{"application/json":{"schema":{"description":"Generic error envelope for 4xx/5xx responses other than request-shape validation.","properties":{"detail":{"oneOf":[{"type":"string","title":"Detail","description":"A human-readable message, OR a structured object carrying a machine-readable `error_kind` (e.g. `idempotency_conflict`, `turn_index_mismatch`, `decision_invalid`).","isRequired":true,"uniqueKey":"detail.oneOf.0","typeLabel":"string"},{"type":"object","title":"Detail","description":"A human-readable message, OR a structured object carrying a machine-readable `error_kind` (e.g. `idempotency_conflict`, `turn_index_mismatch`, `decision_invalid`).","additionalProperties":true,"isRequired":true,"uniqueKey":"detail.oneOf.1","typeLabel":"Detail · object"}],"isRequired":true,"uniqueKey":"detail","typeLabel":"string | Detail · object"},"request_id":{"description":"Correlation id; identical to the `X-Request-Id` response header. Quote it in support requests.","title":"Request Id","type":"string","isRequired":true,"uniqueKey":"request_id","typeLabel":"string"},"docs_url":{"description":"Link to this error's entry in the error catalog. Present whenever `detail` carries a registered `error_kind`; absent on unclassified errors.","title":"Docs Url","type":"string","uniqueKey":"docs_url","typeLabel":"string"}},"required":["detail","request_id"],"title":"Error","type":"object","uniqueKey":"","typeLabel":"Error · object"},"examples":{"Example":{"title":"Example","value":{"detail":"\u003cstring>","request_id":"\u003cstring>","docs_url":"\u003cstring>"}}},"exampleType":"generated"}},"description":"The API key lacks the `people:read` scope (`detail.error_kind = 'insufficient_scope'`, with `detail.required_scope = 'people:read'`). Mint a key that includes it; an ish user access token is unconstrained by scopes.","headers":{"X-Request-Id":{"description":"Per-response correlation id, present on EVERY response (success and error). Error bodies echo it as `request_id`.","schema":{"type":"string"}},"x-ratelimit-limit":{"description":"Ceiling for the rate-limit window this request charged. Present on responses made with an API key against a rate-limited operation, including the `429` itself; absent for user access tokens (which carry no per-key budget) and when the rate-limit backend could not be read.","schema":{"type":"integer"}},"x-ratelimit-remaining":{"description":"Requests left in that window AFTER this one was counted. Pace off this rather than waiting for a `429`.","schema":{"type":"integer"}},"x-ratelimit-reset":{"description":"**Seconds from now** until that window resets (a delta, NOT a Unix timestamp). Measured when the response is written. Omitted on the rare occasion the reset instant could not be read, while `limit` and `remaining` are still published.","schema":{"type":"integer"}}},"exampleType":"generated"},"5d982ca9-f14c-467c-9c50-4894c80b472b":{"content":{"application/json":{"schema":{"description":"Generic error envelope for 4xx/5xx responses other than request-shape validation.","properties":{"detail":{"oneOf":[{"type":"string","title":"Detail","description":"A human-readable message, OR a structured object carrying a machine-readable `error_kind` (e.g. `idempotency_conflict`, `turn_index_mismatch`, `decision_invalid`).","isRequired":true,"uniqueKey":"detail.oneOf.0","typeLabel":"string"},{"type":"object","title":"Detail","description":"A human-readable message, OR a structured object carrying a machine-readable `error_kind` (e.g. `idempotency_conflict`, `turn_index_mismatch`, `decision_invalid`).","additionalProperties":true,"isRequired":true,"uniqueKey":"detail.oneOf.1","typeLabel":"Detail · object"}],"isRequired":true,"uniqueKey":"detail","typeLabel":"string | Detail · object"},"request_id":{"description":"Correlation id; identical to the `X-Request-Id` response header. Quote it in support requests.","title":"Request Id","type":"string","isRequired":true,"uniqueKey":"request_id","typeLabel":"string"},"docs_url":{"description":"Link to this error's entry in the error catalog. Present whenever `detail` carries a registered `error_kind`; absent on unclassified errors.","title":"Docs Url","type":"string","uniqueKey":"docs_url","typeLabel":"string"}},"required":["detail","request_id"],"title":"Error","type":"object","uniqueKey":"","typeLabel":"Error · object"},"examples":{"Example":{"title":"Example","value":{"detail":"\u003cstring>","request_id":"\u003cstring>","docs_url":"\u003cstring>"}}},"exampleType":"generated"}},"description":"The workspace (`workspace_id`) was not found, or is not reachable with this credential. `detail.error_kind` is `workspace_not_found`.","headers":{"X-Request-Id":{"description":"Per-response correlation id, present on EVERY response (success and error). Error bodies echo it as `request_id`.","schema":{"type":"string"}},"x-ratelimit-limit":{"description":"Ceiling for the rate-limit window this request charged. Present on responses made with an API key against a rate-limited operation, including the `429` itself; absent for user access tokens (which carry no per-key budget) and when the rate-limit backend could not be read.","schema":{"type":"integer"}},"x-ratelimit-remaining":{"description":"Requests left in that window AFTER this one was counted. Pace off this rather than waiting for a `429`.","schema":{"type":"integer"}},"x-ratelimit-reset":{"description":"**Seconds from now** until that window resets (a delta, NOT a Unix timestamp). Measured when the response is written. Omitted on the rare occasion the reset instant could not be read, while `limit` and `remaining` are still published.","schema":{"type":"integer"}}},"exampleType":"generated"},"d038422d-397f-4332-ad6d-bd328acba2b0":{"content":{"application/json":{"schema":{"properties":{"detail":{"items":{"description":"Request body / parameter validation failure (HTTP 422). A field-level envelope so callers can pinpoint the offending field, value, and allowed values without parsing prose.","properties":{"detail":{"title":"Detail","type":"string","isRequired":true,"uniqueKey":"detail.items.[INDEX].detail","typeLabel":"string"},"error":{"title":"Error","type":"string","isRequired":true,"uniqueKey":"detail.items.[INDEX].error","typeLabel":"string"},"error_code":{"description":"Stable machine code, e.g. `validation_error`.","title":"Error Code","type":"string","isRequired":true,"uniqueKey":"detail.items.[INDEX].error_code","typeLabel":"string"},"errors":{"items":{"description":"One field-level entry in a ValidationError envelope.","properties":{"loc":{"description":"Path to the offending field.","items":{"oneOf":[{"type":"string","uniqueKey":"detail.items.[INDEX].errors.items.[INDEX].loc.items.[INDEX].oneOf.0","typeLabel":"string"},{"type":"integer","uniqueKey":"detail.items.[INDEX].errors.items.[INDEX].loc.items.[INDEX].oneOf.1","typeLabel":"integer"}],"uniqueKey":"detail.items.[INDEX].errors.items.[INDEX].loc.items.[INDEX]","typeLabel":"string | integer"},"title":"Location","type":"array","isRequired":true,"uniqueKey":"detail.items.[INDEX].errors.items.[INDEX].loc","typeLabel":"(string | integer)[]"},"msg":{"title":"Message","type":"string","isRequired":true,"uniqueKey":"detail.items.[INDEX].errors.items.[INDEX].msg","typeLabel":"string"},"type":{"title":"Error Type","type":"string","isRequired":true,"uniqueKey":"detail.items.[INDEX].errors.items.[INDEX].type","typeLabel":"string"},"allowed_values":{"description":"For enum/literal failures, the accepted values.","items":{"oneOf":[{}],"uniqueKey":"detail.items.[INDEX].errors.items.[INDEX].allowed_values.items.[INDEX]","typeLabel":"any"},"title":"Allowed Values","type":"array","uniqueKey":"detail.items.[INDEX].errors.items.[INDEX].allowed_values","typeLabel":"any[]"},"input":{"oneOf":[{"type":"string","title":"Input","description":"Offending value (truncated); omitted for containers.","uniqueKey":"detail.items.[INDEX].errors.items.[INDEX].input.oneOf.0","typeLabel":"string"},{"type":"number","title":"Input","description":"Offending value (truncated); omitted for containers.","uniqueKey":"detail.items.[INDEX].errors.items.[INDEX].input.oneOf.1","typeLabel":"number"},{"type":"boolean","title":"Input","description":"Offending value (truncated); omitted for containers.","uniqueKey":"detail.items.[INDEX].errors.items.[INDEX].input.oneOf.2","typeLabel":"boolean"},{"type":"null","title":"Input","description":"Offending value (truncated); omitted for containers.","uniqueKey":"detail.items.[INDEX].errors.items.[INDEX].input.oneOf.3","typeLabel":"null"}],"uniqueKey":"detail.items.[INDEX].errors.items.[INDEX].input","typeLabel":"string | number | boolean | null"}},"required":["loc","msg","type"],"title":"FieldError","type":"object","uniqueKey":"detail.items.[INDEX].errors.items.[INDEX]","typeLabel":"FieldError · object"},"title":"Errors","type":"array","isRequired":true,"uniqueKey":"detail.items.[INDEX].errors","typeLabel":"FieldError · object[]"},"retryable":{"title":"Retryable","type":"boolean","isRequired":true,"uniqueKey":"detail.items.[INDEX].retryable","typeLabel":"boolean"},"status":{"title":"Status","type":"integer","isRequired":true,"uniqueKey":"detail.items.[INDEX].status","typeLabel":"integer"},"suggestions":{"items":{"type":"string","uniqueKey":"detail.items.[INDEX].suggestions.items.[INDEX]","typeLabel":"string"},"title":"Suggestions","type":"array","uniqueKey":"detail.items.[INDEX].suggestions","typeLabel":"string[]"}},"required":["error","error_code","status","retryable","detail","errors"],"title":"ValidationError","type":"object","uniqueKey":"detail.items.[INDEX]","typeLabel":"ValidationError · object"},"title":"Detail","type":"array","uniqueKey":"detail","typeLabel":"ValidationError · object[]"}},"title":"HTTPValidationError","type":"object","uniqueKey":"","typeLabel":"HTTPValidationError · object"},"examples":{"Example":{"title":"Example","value":{"detail":[{"detail":"\u003cstring>","error":"\u003cstring>","error_code":"\u003cstring>","errors":[{"loc":["\u003cstring>"],"msg":"\u003cstring>","type":"\u003cstring>","allowed_values":["\u003cunknown>"],"input":"\u003cstring>"}],"retryable":true,"status":123,"suggestions":["\u003cstring>"]}]}}},"exampleType":"generated"}},"description":"Validation Error","headers":{"X-Request-Id":{"description":"Per-response correlation id, present on EVERY response (success and error). Error bodies echo it as `request_id`.","schema":{"type":"string"}},"x-ratelimit-limit":{"description":"Ceiling for the rate-limit window this request charged. Present on responses made with an API key against a rate-limited operation, including the `429` itself; absent for user access tokens (which carry no per-key budget) and when the rate-limit backend could not be read.","schema":{"type":"integer"}},"x-ratelimit-remaining":{"description":"Requests left in that window AFTER this one was counted. Pace off this rather than waiting for a `429`.","schema":{"type":"integer"}},"x-ratelimit-reset":{"description":"**Seconds from now** until that window resets (a delta, NOT a Unix timestamp). Measured when the response is written. Omitted on the rare occasion the reset instant could not be read, while `limit` and `remaining` are still published.","schema":{"type":"integer"}}},"exampleType":"generated"},"34bc82e2-8014-4387-8604-b429444b2b1f":{"content":{"application/json":{"schema":{"description":"Generic error envelope for 4xx/5xx responses other than request-shape validation.","properties":{"detail":{"oneOf":[{"type":"string","title":"Detail","description":"A human-readable message, OR a structured object carrying a machine-readable `error_kind` (e.g. `idempotency_conflict`, `turn_index_mismatch`, `decision_invalid`).","isRequired":true,"uniqueKey":"detail.oneOf.0","typeLabel":"string"},{"type":"object","title":"Detail","description":"A human-readable message, OR a structured object carrying a machine-readable `error_kind` (e.g. `idempotency_conflict`, `turn_index_mismatch`, `decision_invalid`).","additionalProperties":true,"isRequired":true,"uniqueKey":"detail.oneOf.1","typeLabel":"Detail · object"}],"isRequired":true,"uniqueKey":"detail","typeLabel":"string | Detail · object"},"request_id":{"description":"Correlation id; identical to the `X-Request-Id` response header. Quote it in support requests.","title":"Request Id","type":"string","isRequired":true,"uniqueKey":"request_id","typeLabel":"string"},"docs_url":{"description":"Link to this error's entry in the error catalog. Present whenever `detail` carries a registered `error_kind`; absent on unclassified errors.","title":"Docs Url","type":"string","uniqueKey":"docs_url","typeLabel":"string"}},"required":["detail","request_id"],"title":"Error","type":"object","uniqueKey":"","typeLabel":"Error · object"},"examples":{"Example":{"title":"Example","value":{"detail":"\u003cstring>","request_id":"\u003cstring>","docs_url":"\u003cstring>"}}},"exampleType":"generated"}},"description":"The API key's request rate limit is exceeded (`detail.error_kind = 'rate_limited'`). Transient: retry after the `Retry-After` interval, also echoed as `detail.retry_after_seconds`. Not applied to user access tokens.","headers":{"X-Request-Id":{"description":"Per-response correlation id, present on EVERY response (success and error). Error bodies echo it as `request_id`.","schema":{"type":"string"}},"x-ratelimit-limit":{"description":"Ceiling for the rate-limit window this request charged. Present on responses made with an API key against a rate-limited operation, including the `429` itself; absent for user access tokens (which carry no per-key budget) and when the rate-limit backend could not be read.","schema":{"type":"integer"}},"x-ratelimit-remaining":{"description":"Requests left in that window AFTER this one was counted. Pace off this rather than waiting for a `429`.","schema":{"type":"integer"}},"x-ratelimit-reset":{"description":"**Seconds from now** until that window resets (a delta, NOT a Unix timestamp). Measured when the response is written. Omitted on the rare occasion the reset instant could not be read, while `limit` and `remaining` are still published.","schema":{"type":"integer"}}},"exampleType":"generated"}},"security":{"f946cc05-85e3-4aaa-a739-c076c4a05a30":{"bearerAuth":{"description":"Workspace API key as a bearer token: `Authorization: Bearer ish_sk_live_...`. Keys are workspace-scoped machine principals minted in Settings > Developers (shown once at mint). Scopes: `sessions:run` (create a session, submit turns, close), `sessions:read` (read the session and its decision trace), `environments:read` and `environments:write` (manage the workspace's registered environments), `tasks:read` and `tasks:write` (manage the workspace's registered tasks), `people:read` and `people:write` (the people the workspace can run a session for), and `usage:read` (the workspace's own consumption, spend limits and rate-limit budgets). A key is minted with `sessions:run`, `sessions:read`, and `tasks:read` by default; every other scope must be requested, `people:read` and `usage:read` included. An ish user access token also works on the same header for personal scripts.","scheme":"bearer","type":"http","scopes":[],"schemeName":"bearerAuth"}}},"servers":{"22c3a961-b6d9-4922-b5aa-d0aac292aa39":{"description":"Production","url":"https://api.ishlabs.io"}},"processedSecurityOptions":[{"schemes":[{"scheme":{"description":"Workspace API key as a bearer token: `Authorization: Bearer ish_sk_live_...`. Keys are workspace-scoped machine principals minted in Settings > Developers (shown once at mint). Scopes: `sessions:run` (create a session, submit turns, close), `sessions:read` (read the session and its decision trace), `environments:read` and `environments:write` (manage the workspace's registered environments), `tasks:read` and `tasks:write` (manage the workspace's registered tasks), `people:read` and `people:write` (the people the workspace can run a session for), and `usage:read` (the workspace's own consumption, spend limits and rate-limit budgets). A key is minted with `sessions:run`, `sessions:read`, and `tasks:read` by default; every other scope must be requested, `people:read` and `usage:read` included. An ish user access token also works on the same header for personal scripts.","scheme":"bearer","type":"http","scopes":[],"schemeName":"bearerAuth"},"schema":{"title":"Bearer Auth","type":"string","isRequired":true,"description":"Workspace API key as a bearer token: `Authorization: Bearer ish_sk_live_...`. Keys are workspace-scoped machine principals minted in Settings > Developers (shown once at mint). Scopes: `sessions:run` (create a session, submit turns, close), `sessions:read` (read the session and its decision trace), `environments:read` and `environments:write` (manage the workspace's registered environments), `tasks:read` and `tasks:write` (manage the workspace's registered tasks), `people:read` and `people:write` (the people the workspace can run a session for), and `usage:read` (the workspace's own consumption, spend limits and rate-limit budgets). A key is minted with `sessions:run`, `sessions:read`, and `tasks:read` by default; every other scope must be requested, `people:read` and `usage:read` included. An ish user access token also works on the same header for personal scripts.","format":"bearer","typeLabel":"string\u003cbearer>","deprecated":false},"schemeName":"bearerAuth","name":"Authorization"}],"title":"bearerAuth"}]},"originalFileLocation":"api/openapi.public.json"},"subdomain":"ish","siteName":"ish","title":"Search People - ish","navMaps":{"firstHrefInVersion":{},"firstHrefInLanguage":{}},"lastModified":"2026-10-08T15:42:21.354Z","originalFileLocation":"api/reference/people/search-people.mdx"},"headHtml":"\u003cscript data-mint-head>(function(){var d=document.documentElement,p=null;if(!p){try{p=localStorage.getItem(\"isDarkMode\")}catch(e){}if(p==='true')p='dark';else if(p==='false')p='light';if(p!=='light'\u0026\u0026p!=='dark'\u0026\u0026p!=='system')p=\"system\"}var r=p==='system'?(matchMedia(\"(prefers-color-scheme: dark)\").matches?'dark':'light'):p;d.classList.remove(r==='dark'?'light':'dark');d.classList.add(r);d.setAttribute(\"data-theme-preference\",p)})();\u003c/script>\u003cmeta data-mint-head name=\"description\" content=\"Find people by their attributes, using a boolean rule tree. Searches the same pool the list endpoint serves (your workspace\u0026#x27;s people plus the platform library), and returns the same paginated envelope. ## The rule tree A rule is a single node. A node is either a leaf or a group, never both: - A leaf tests one attribute: {\u0026quot;field\u0026quot;: {\u0026quot;source\u0026quot;: ..., \u0026quot;key\u0026quot;: ...}, \u0026quot;operator\u0026quot;: ..., \u0026quot;value\u0026quot;: ...}. Copy source and key from the attribute\u0026#x27;s filter block in GET .../people/schema; that endpoint is the authoritative vocabulary, and an attribute or operator it does not list is refused with a 422 rather than matching nothing. - A group combines nodes: {\u0026quot;op\u0026quot;: \u0026quot;and\u0026quot; | \u0026quot;or\u0026quot; | \u0026quot;not\u0026quot;, \u0026quot;conditions\u0026quot;: [...]}. ## Boolean semantics, exactly A group\u0026#x27;s op applies to its OWN conditions and to nothing else. and matches a person satisfying every condition in that group; or matches a person satisfying at least one; not takes exactly one condition and matches people who do not satisfy it. Groups nest, so a group inside another group is evaluated on its own first and its result is then one input to the parent\u0026#x27;s operator. There is no precedence to remember and no implicit combination anywhere: two conditions are only ever joined by the op of the group holding them. ## A worked example \u0026quot;Nurses in Sweden, plus teachers in Norway\u0026quot; is two AND-groups joined by an OR. Note that the country is repeated in both groups: the outer or does not distribute over anything, so a condition placed outside the groups would not apply to either. json { \u0026quot;rule\u0026quot;: { \u0026quot;op\u0026quot;: \u0026quot;or\u0026quot;, \u0026quot;conditions\u0026quot;: [ {\u0026quot;op\u0026quot;: \u0026quot;and\u0026quot;, \u0026quot;conditions\u0026quot;: [ {\u0026quot;field\u0026quot;: {\u0026quot;source\u0026quot;: \u0026quot;demographic\u0026quot;, \u0026quot;key\u0026quot;: \u0026quot;occupation\u0026quot;}, \u0026quot;operator\u0026quot;: \u0026quot;eq\u0026quot;, \u0026quot;value\u0026quot;: \u0026quot;nurse\u0026quot;}, {\u0026quot;field\u0026quot;: {\u0026quot;source\u0026quot;: \u0026quot;demographic\u0026quot;, \u0026quot;key\u0026quot;: \u0026quot;country\u0026quot;}, \u0026quot;operator\u0026quot;: \u0026quot;eq\u0026quot;, \u0026quot;value\u0026quot;: \u0026quot;Sweden\u0026quot;} ]}, {\u0026quot;op\u0026quot;: \u0026quot;and\u0026quot;, \u0026quot;conditions\u0026quot;: [ {\u0026quot;field\u0026quot;: {\u0026quot;source\u0026quot;: \u0026quot;demographic\u0026quot;, \u0026quot;key\u0026quot;: \u0026quot;occupation\u0026quot;}, \u0026quot;operator\u0026quot;: \u0026quot;eq\u0026quot;, \u0026quot;value\u0026quot;: \u0026quot;teacher\u0026quot;}, {\u0026quot;field\u0026quot;: {\u0026quot;source\u0026quot;: \u0026quot;demographic\u0026quot;, \u0026quot;key\u0026quot;: \u0026quot;country\u0026quot;}, \u0026quot;operator\u0026quot;: \u0026quot;eq\u0026quot;, \u0026quot;value\u0026quot;: \u0026quot;Norway\u0026quot;} ]} ] }, \u0026quot;pagination\u0026quot;: {\u0026quot;limit\u0026quot;: 25} } ## Testing whether an attribute is set is_not_null matches people who have a value for an attribute, and is_null matches people who do not. Reach for these rather than comparing against an empty string: an attribute nobody filled in holds no value at all, and it satisfies no ordinary comparison, not even a negated one. ## Limits, and how a rule is refused A rule may nest groups at most 2 levels deep, hold at most 15 conditions in any one group, and 25 in total. Both refusals are a 422 carrying an error_kind, and they have different fixes: - search_rule_too_complex: past one of those caps. The detail names the offending count and the limit. Combining values with in costs one condition instead of one per value, and is the usual fix. - search_rule_invalid: the tree is malformed, or it names an attribute, source or operator this API does not publish. The detail names the offender, and GET .../people/schema is the vocabulary it was checked against. A malformed request BODY (rather than a bad rule) is the ordinary validation 422 with the field-level envelope, which is why this operation\u0026#x27;s 422 documents either shape. ## Saved segments Segments live in the ish app and are not exposed here. A segment IS a rule, so the way to use one is to send its rule as the rule on this request: that is how the ish console itself applies them.\">\u003cmeta data-mint-head name=\"application-name\" content=\"ish\">\u003cmeta data-mint-head name=\"generator\" content=\"Mintlify\">\u003clink data-mint-head rel=\"icon\" type=\"image/png\" sizes=\"192x192\" href=\"/mintlify-assets/_mintlify/favicons/ish/pQaVEm2sa1ahpXnl/_generated/favicon/android-chrome-192x192.png\" media=\"(prefers-color-scheme: light)\">\u003clink data-mint-head rel=\"apple-touch-icon\" type=\"image/png\" sizes=\"180x180\" href=\"/mintlify-assets/_mintlify/favicons/ish/pQaVEm2sa1ahpXnl/_generated/favicon/apple-touch-icon.png\">\u003clink data-mint-head rel=\"icon\" type=\"image/png\" sizes=\"16x16\" href=\"/mintlify-assets/_mintlify/favicons/ish/pQaVEm2sa1ahpXnl/_generated/favicon/favicon-16x16.png\" media=\"(prefers-color-scheme: light)\">\u003clink data-mint-head rel=\"icon\" type=\"image/png\" sizes=\"32x32\" href=\"/mintlify-assets/_mintlify/favicons/ish/pQaVEm2sa1ahpXnl/_generated/favicon/favicon-32x32.png\" media=\"(prefers-color-scheme: light)\">\u003clink data-mint-head rel=\"shortcut icon\" type=\"image/x-icon\" href=\"/mintlify-assets/_mintlify/favicons/ish/pQaVEm2sa1ahpXnl/_generated/favicon/favicon.ico\" media=\"(prefers-color-scheme: light)\">\u003clink data-mint-head rel=\"icon\" type=\"image/png\" sizes=\"192x192\" href=\"/mintlify-assets/_mintlify/favicons/ish/pQaVEm2sa1ahpXnl/_generated/favicon-dark/android-chrome-192x192.png\" media=\"(prefers-color-scheme: dark)\">\u003clink data-mint-head rel=\"icon\" type=\"image/png\" sizes=\"16x16\" href=\"/mintlify-assets/_mintlify/favicons/ish/pQaVEm2sa1ahpXnl/_generated/favicon-dark/favicon-16x16.png\" media=\"(prefers-color-scheme: dark)\">\u003clink data-mint-head rel=\"icon\" type=\"image/png\" sizes=\"32x32\" href=\"/mintlify-assets/_mintlify/favicons/ish/pQaVEm2sa1ahpXnl/_generated/favicon-dark/favicon-32x32.png\" media=\"(prefers-color-scheme: dark)\">\u003clink data-mint-head rel=\"shortcut icon\" type=\"image/x-icon\" href=\"/mintlify-assets/_mintlify/favicons/ish/pQaVEm2sa1ahpXnl/_generated/favicon-dark/favicon.ico\" media=\"(prefers-color-scheme: dark)\">\u003cmeta data-mint-head property=\"og:title\" content=\"Search People - ish\">\u003cmeta data-mint-head property=\"og:description\" content=\"Find people by their attributes, using a boolean rule tree. Searches the same pool the list endpoint serves (your workspace\u0026#x27;s people plus the platform library), and returns the same paginated envelope. ## The rule tree A rule is a single node. A node is either a leaf or a group, never both: - A leaf tests one attribute: {\u0026quot;field\u0026quot;: {\u0026quot;source\u0026quot;: ..., \u0026quot;key\u0026quot;: ...}, \u0026quot;operator\u0026quot;: ..., \u0026quot;value\u0026quot;: ...}. Copy source and key from the attribute\u0026#x27;s filter block in GET .../people/schema; that endpoint is the authoritative vocabulary, and an attribute or operator it does not list is refused with a 422 rather than matching nothing. - A group combines nodes: {\u0026quot;op\u0026quot;: \u0026quot;and\u0026quot; | \u0026quot;or\u0026quot; | \u0026quot;not\u0026quot;, \u0026quot;conditions\u0026quot;: [...]}. ## Boolean semantics, exactly A group\u0026#x27;s op applies to its OWN conditions and to nothing else. and matches a person satisfying every condition in that group; or matches a person satisfying at least one; not takes exactly one condition and matches people who do not satisfy it. Groups nest, so a group inside another group is evaluated on its own first and its result is then one input to the parent\u0026#x27;s operator. There is no precedence to remember and no implicit combination anywhere: two conditions are only ever joined by the op of the group holding them. ## A worked example \u0026quot;Nurses in Sweden, plus teachers in Norway\u0026quot; is two AND-groups joined by an OR. Note that the country is repeated in both groups: the outer or does not distribute over anything, so a condition placed outside the groups would not apply to either. json { \u0026quot;rule\u0026quot;: { \u0026quot;op\u0026quot;: \u0026quot;or\u0026quot;, \u0026quot;conditions\u0026quot;: [ {\u0026quot;op\u0026quot;: \u0026quot;and\u0026quot;, \u0026quot;conditions\u0026quot;: [ {\u0026quot;field\u0026quot;: {\u0026quot;source\u0026quot;: \u0026quot;demographic\u0026quot;, \u0026quot;key\u0026quot;: \u0026quot;occupation\u0026quot;}, \u0026quot;operator\u0026quot;: \u0026quot;eq\u0026quot;, \u0026quot;value\u0026quot;: \u0026quot;nurse\u0026quot;}, {\u0026quot;field\u0026quot;: {\u0026quot;source\u0026quot;: \u0026quot;demographic\u0026quot;, \u0026quot;key\u0026quot;: \u0026quot;country\u0026quot;}, \u0026quot;operator\u0026quot;: \u0026quot;eq\u0026quot;, \u0026quot;value\u0026quot;: \u0026quot;Sweden\u0026quot;} ]}, {\u0026quot;op\u0026quot;: \u0026quot;and\u0026quot;, \u0026quot;conditions\u0026quot;: [ {\u0026quot;field\u0026quot;: {\u0026quot;source\u0026quot;: \u0026quot;demographic\u0026quot;, \u0026quot;key\u0026quot;: \u0026quot;occupation\u0026quot;}, \u0026quot;operator\u0026quot;: \u0026quot;eq\u0026quot;, \u0026quot;value\u0026quot;: \u0026quot;teacher\u0026quot;}, {\u0026quot;field\u0026quot;: {\u0026quot;source\u0026quot;: \u0026quot;demographic\u0026quot;, \u0026quot;key\u0026quot;: \u0026quot;country\u0026quot;}, \u0026quot;operator\u0026quot;: \u0026quot;eq\u0026quot;, \u0026quot;value\u0026quot;: \u0026quot;Norway\u0026quot;} ]} ] }, \u0026quot;pagination\u0026quot;: {\u0026quot;limit\u0026quot;: 25} } ## Testing whether an attribute is set is_not_null matches people who have a value for an attribute, and is_null matches people who do not. Reach for these rather than comparing against an empty string: an attribute nobody filled in holds no value at all, and it satisfies no ordinary comparison, not even a negated one. ## Limits, and how a rule is refused A rule may nest groups at most 2 levels deep, hold at most 15 conditions in any one group, and 25 in total. Both refusals are a 422 carrying an error_kind, and they have different fixes: - search_rule_too_complex: past one of those caps. The detail names the offending count and the limit. Combining values with in costs one condition instead of one per value, and is the usual fix. - search_rule_invalid: the tree is malformed, or it names an attribute, source or operator this API does not publish. The detail names the offender, and GET .../people/schema is the vocabulary it was checked against. A malformed request BODY (rather than a bad rule) is the ordinary validation 422 with the field-level envelope, which is why this operation\u0026#x27;s 422 documents either shape. ## Saved segments Segments live in the ish app and are not exposed here. A segment IS a rule, so the way to use one is to send its rule as the rule on this request: that is how the ish console itself applies them.\">\u003cmeta data-mint-head property=\"og:site_name\" content=\"ish\">\u003cmeta data-mint-head property=\"og:url\" content=\"https://docs.ishlabs.io/api/reference/people/search-people\">\u003cmeta data-mint-head property=\"og:type\" content=\"website\">\u003cmeta data-mint-head property=\"og:image\" content=\"https://ish.mintlify.site/_mintlify/api/og/v2?division=API+reference\u0026amp;title=Search+People\u0026amp;description=Find+people+by+their+attributes%2C+using+a+boolean+rule+tree.%0A%0ASearches+the+same+pool+the+list+endpoint+serves+%28your+workspace%27s+people%0Aplus+the+platform+library%29\u0026amp;theme=e052e8dabadef59794361480\u0026amp;signature=492cf5a455be96e9509d1d1ec26b9c85f2c6d0cb43dcb8f8a87182b1bcbc9543\">\u003cmeta data-mint-head property=\"og:image:width\" content=\"1200\">\u003cmeta data-mint-head property=\"og:image:height\" content=\"630\">\u003cmeta data-mint-head name=\"twitter:card\" content=\"summary_large_image\">\u003cmeta data-mint-head name=\"twitter:title\" content=\"Search People - ish\">\u003cmeta data-mint-head name=\"twitter:description\" content=\"Find people by their attributes, using a boolean rule tree. Searches the same pool the list endpoint serves (your workspace\u0026#x27;s people plus the platform library), and returns the same paginated envelope. ## The rule tree A rule is a single node. A node is either a leaf or a group, never both: - A leaf tests one attribute: {\u0026quot;field\u0026quot;: {\u0026quot;source\u0026quot;: ..., \u0026quot;key\u0026quot;: ...}, \u0026quot;operator\u0026quot;: ..., \u0026quot;value\u0026quot;: ...}. Copy source and key from the attribute\u0026#x27;s filter block in GET .../people/schema; that endpoint is the authoritative vocabulary, and an attribute or operator it does not list is refused with a 422 rather than matching nothing. - A group combines nodes: {\u0026quot;op\u0026quot;: \u0026quot;and\u0026quot; | \u0026quot;or\u0026quot; | \u0026quot;not\u0026quot;, \u0026quot;conditions\u0026quot;: [...]}. ## Boolean semantics, exactly A group\u0026#x27;s op applies to its OWN conditions and to nothing else. and matches a person satisfying every condition in that group; or matches a person satisfying at least one; not takes exactly one condition and matches people who do not satisfy it. Groups nest, so a group inside another group is evaluated on its own first and its result is then one input to the parent\u0026#x27;s operator. There is no precedence to remember and no implicit combination anywhere: two conditions are only ever joined by the op of the group holding them. ## A worked example \u0026quot;Nurses in Sweden, plus teachers in Norway\u0026quot; is two AND-groups joined by an OR. Note that the country is repeated in both groups: the outer or does not distribute over anything, so a condition placed outside the groups would not apply to either. json { \u0026quot;rule\u0026quot;: { \u0026quot;op\u0026quot;: \u0026quot;or\u0026quot;, \u0026quot;conditions\u0026quot;: [ {\u0026quot;op\u0026quot;: \u0026quot;and\u0026quot;, \u0026quot;conditions\u0026quot;: [ {\u0026quot;field\u0026quot;: {\u0026quot;source\u0026quot;: \u0026quot;demographic\u0026quot;, \u0026quot;key\u0026quot;: \u0026quot;occupation\u0026quot;}, \u0026quot;operator\u0026quot;: \u0026quot;eq\u0026quot;, \u0026quot;value\u0026quot;: \u0026quot;nurse\u0026quot;}, {\u0026quot;field\u0026quot;: {\u0026quot;source\u0026quot;: \u0026quot;demographic\u0026quot;, \u0026quot;key\u0026quot;: \u0026quot;country\u0026quot;}, \u0026quot;operator\u0026quot;: \u0026quot;eq\u0026quot;, \u0026quot;value\u0026quot;: \u0026quot;Sweden\u0026quot;} ]}, {\u0026quot;op\u0026quot;: \u0026quot;and\u0026quot;, \u0026quot;conditions\u0026quot;: [ {\u0026quot;field\u0026quot;: {\u0026quot;source\u0026quot;: \u0026quot;demographic\u0026quot;, \u0026quot;key\u0026quot;: \u0026quot;occupation\u0026quot;}, \u0026quot;operator\u0026quot;: \u0026quot;eq\u0026quot;, \u0026quot;value\u0026quot;: \u0026quot;teacher\u0026quot;}, {\u0026quot;field\u0026quot;: {\u0026quot;source\u0026quot;: \u0026quot;demographic\u0026quot;, \u0026quot;key\u0026quot;: \u0026quot;country\u0026quot;}, \u0026quot;operator\u0026quot;: \u0026quot;eq\u0026quot;, \u0026quot;value\u0026quot;: \u0026quot;Norway\u0026quot;} ]} ] }, \u0026quot;pagination\u0026quot;: {\u0026quot;limit\u0026quot;: 25} } ## Testing whether an attribute is set is_not_null matches people who have a value for an attribute, and is_null matches people who do not. Reach for these rather than comparing against an empty string: an attribute nobody filled in holds no value at all, and it satisfies no ordinary comparison, not even a negated one. ## Limits, and how a rule is refused A rule may nest groups at most 2 levels deep, hold at most 15 conditions in any one group, and 25 in total. Both refusals are a 422 carrying an error_kind, and they have different fixes: - search_rule_too_complex: past one of those caps. The detail names the offending count and the limit. Combining values with in costs one condition instead of one per value, and is the usual fix. - search_rule_invalid: the tree is malformed, or it names an attribute, source or operator this API does not publish. The detail names the offender, and GET .../people/schema is the vocabulary it was checked against. A malformed request BODY (rather than a bad rule) is the ordinary validation 422 with the field-level envelope, which is why this operation\u0026#x27;s 422 documents either shape. ## Saved segments Segments live in the ish app and are not exposed here. A segment IS a rule, so the way to use one is to send its rule as the rule on this request: that is how the ish console itself applies them.\">\u003cmeta data-mint-head name=\"twitter:image\" content=\"https://ish.mintlify.site/_mintlify/api/og/v2?division=API+reference\u0026amp;title=Search+People\u0026amp;description=Find+people+by+their+attributes%2C+using+a+boolean+rule+tree.%0A%0ASearches+the+same+pool+the+list+endpoint+serves+%28your+workspace%27s+people%0Aplus+the+platform+library%29\u0026amp;theme=e052e8dabadef59794361480\u0026amp;signature=492cf5a455be96e9509d1d1ec26b9c85f2c6d0cb43dcb8f8a87182b1bcbc9543\">\u003cmeta data-mint-head name=\"twitter:image:width\" content=\"1200\">\u003cmeta data-mint-head name=\"twitter:image:height\" content=\"630\">\u003cmeta data-mint-head name=\"msapplication-config\" content=\"/mintlify-assets/_mintlify/favicons/ish/pQaVEm2sa1ahpXnl/_generated/favicon/browserconfig.xml\">\u003cmeta data-mint-head name=\"apple-mobile-web-app-title\" content=\"ish\">\u003cmeta data-mint-head name=\"msapplication-TileColor\" content=\"#C8623F\">\u003clink data-mint-head rel=\"canonical\" href=\"https://docs.ishlabs.io/api/reference/people/search-people\">\u003clink data-mint-head rel=\"alternate\" type=\"application/xml\" href=\"/sitemap.xml\">\u003clink data-mint-head rel=\"alternate\" type=\"text/markdown\" href=\"/api/reference/people/search-people.md\">\u003cscript data-mint-head type=\"application/ld+json\">{\"@context\":\"https://schema.org\",\"@graph\":[{\"@type\":\"Organization\",\"@id\":\"https://docs.ishlabs.io/#organization\",\"name\":\"ish\",\"url\":\"https://docs.ishlabs.io\",\"logo\":{\"@type\":\"ImageObject\",\"url\":\"https://mintcdn.com/ish/4MaJn6-B7_NnPAml/logo/light.svg?fit=max\u0026auto=format\u0026n=4MaJn6-B7_NnPAml\u0026q=85\u0026s=f0edab6b74c19bec95794ee94d7270c2\"}},{\"@type\":\"WebSite\",\"@id\":\"https://docs.ishlabs.io#website\",\"name\":\"ish\",\"url\":\"https://docs.ishlabs.io\",\"publisher\":{\"@id\":\"https://docs.ishlabs.io/#organization\"}},{\"@type\":\"WebPage\",\"@id\":\"https://docs.ishlabs.io/api/reference/people/search-people#webpage\",\"url\":\"https://docs.ishlabs.io/api/reference/people/search-people\",\"name\":\"Search People\",\"description\":\"Find people by their attributes, using a boolean rule tree. Searches the same pool the list endpoint serves (your workspace's people plus the platform library), and returns the same paginated envelope. ## The rule tree A rule is a single node. A node is either a leaf or a group, never both: - A leaf tests one attribute: {\\\"field\\\": {\\\"source\\\": ..., \\\"key\\\": ...}, \\\"operator\\\": ..., \\\"value\\\": ...}. Copy source and key from the attribute's filter block in GET .../people/schema; that endpoint is the authoritative vocabulary, and an attribute or operator it does not list is refused with a 422 rather than matching nothing. - A group combines nodes: {\\\"op\\\": \\\"and\\\" | \\\"or\\\" | \\\"not\\\", \\\"conditions\\\": [...]}. ## Boolean semantics, exactly A group's op applies to its OWN conditions and to nothing else. and matches a person satisfying every condition in that group; or matches a person satisfying at least one; not takes exactly one condition and matches people who do not satisfy it. Groups nest, so a group inside another group is evaluated on its own first and its result is then one input to the parent's operator. There is no precedence to remember and no implicit combination anywhere: two conditions are only ever joined by the op of the group holding them. ## A worked example \\\"Nurses in Sweden, plus teachers in Norway\\\" is two AND-groups joined by an OR. Note that the country is repeated in both groups: the outer or does not distribute over anything, so a condition placed outside the groups would not apply to either. json { \\\"rule\\\": { \\\"op\\\": \\\"or\\\", \\\"conditions\\\": [ {\\\"op\\\": \\\"and\\\", \\\"conditions\\\": [ {\\\"field\\\": {\\\"source\\\": \\\"demographic\\\", \\\"key\\\": \\\"occupation\\\"}, \\\"operator\\\": \\\"eq\\\", \\\"value\\\": \\\"nurse\\\"}, {\\\"field\\\": {\\\"source\\\": \\\"demographic\\\", \\\"key\\\": \\\"country\\\"}, \\\"operator\\\": \\\"eq\\\", \\\"value\\\": \\\"Sweden\\\"} ]}, {\\\"op\\\": \\\"and\\\", \\\"conditions\\\": [ {\\\"field\\\": {\\\"source\\\": \\\"demographic\\\", \\\"key\\\": \\\"occupation\\\"}, \\\"operator\\\": \\\"eq\\\", \\\"value\\\": \\\"teacher\\\"}, {\\\"field\\\": {\\\"source\\\": \\\"demographic\\\", \\\"key\\\": \\\"country\\\"}, \\\"operator\\\": \\\"eq\\\", \\\"value\\\": \\\"Norway\\\"} ]} ] }, \\\"pagination\\\": {\\\"limit\\\": 25} } ## Testing whether an attribute is set is_not_null matches people who have a value for an attribute, and is_null matches people who do not. Reach for these rather than comparing against an empty string: an attribute nobody filled in holds no value at all, and it satisfies no ordinary comparison, not even a negated one. ## Limits, and how a rule is refused A rule may nest groups at most 2 levels deep, hold at most 15 conditions in any one group, and 25 in total. Both refusals are a 422 carrying an error_kind, and they have different fixes: - search_rule_too_complex: past one of those caps. The detail names the offending count and the limit. Combining values with in costs one condition instead of one per value, and is the usual fix. - search_rule_invalid: the tree is malformed, or it names an attribute, source or operator this API does not publish. The detail names the offender, and GET .../people/schema is the vocabulary it was checked against. A malformed request BODY (rather than a bad rule) is the ordinary validation 422 with the field-level envelope, which is why this operation's 422 documents either shape. ## Saved segments Segments live in the ish app and are not exposed here. A segment IS a rule, so the way to use one is to send its rule as the rule on this request: that is how the ish console itself applies them.\",\"dateModified\":\"2026-10-08T15:42:21.354Z\",\"isPartOf\":{\"@id\":\"https://docs.ishlabs.io#website\"},\"breadcrumb\":{\"@id\":\"https://docs.ishlabs.io/api/reference/people/search-people#breadcrumb\"}},{\"@type\":\"BreadcrumbList\",\"@id\":\"https://docs.ishlabs.io/api/reference/people/search-people#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"API reference\",\"item\":\"https://docs.ishlabs.io/api/reference/introduction\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Search People\",\"item\":\"https://docs.ishlabs.io/api/reference/people/search-people\"}]},{\"@type\":[\"TechArticle\",\"APIReference\"],\"@id\":\"https://docs.ishlabs.io/api/reference/people/search-people#apireference\",\"headline\":\"Search People\",\"name\":\"Search People\",\"description\":\"Find people by their attributes, using a boolean rule tree. Searches the same pool the list endpoint serves (your workspace's people plus the platform library), and returns the same paginated envelope. ## The rule tree A rule is a single node. A node is either a leaf or a group, never both: - A leaf tests one attribute: {\\\"field\\\": {\\\"source\\\": ..., \\\"key\\\": ...}, \\\"operator\\\": ..., \\\"value\\\": ...}. Copy source and key from the attribute's filter block in GET .../people/schema; that endpoint is the authoritative vocabulary, and an attribute or operator it does not list is refused with a 422 rather than matching nothing. - A group combines nodes: {\\\"op\\\": \\\"and\\\" | \\\"or\\\" | \\\"not\\\", \\\"conditions\\\": [...]}. ## Boolean semantics, exactly A group's op applies to its OWN conditions and to nothing else. and matches a person satisfying every condition in that group; or matches a person satisfying at least one; not takes exactly one condition and matches people who do not satisfy it. Groups nest, so a group inside another group is evaluated on its own first and its result is then one input to the parent's operator. There is no precedence to remember and no implicit combination anywhere: two conditions are only ever joined by the op of the group holding them. ## A worked example \\\"Nurses in Sweden, plus teachers in Norway\\\" is two AND-groups joined by an OR. Note that the country is repeated in both groups: the outer or does not distribute over anything, so a condition placed outside the groups would not apply to either. json { \\\"rule\\\": { \\\"op\\\": \\\"or\\\", \\\"conditions\\\": [ {\\\"op\\\": \\\"and\\\", \\\"conditions\\\": [ {\\\"field\\\": {\\\"source\\\": \\\"demographic\\\", \\\"key\\\": \\\"occupation\\\"}, \\\"operator\\\": \\\"eq\\\", \\\"value\\\": \\\"nurse\\\"}, {\\\"field\\\": {\\\"source\\\": \\\"demographic\\\", \\\"key\\\": \\\"country\\\"}, \\\"operator\\\": \\\"eq\\\", \\\"value\\\": \\\"Sweden\\\"} ]}, {\\\"op\\\": \\\"and\\\", \\\"conditions\\\": [ {\\\"field\\\": {\\\"source\\\": \\\"demographic\\\", \\\"key\\\": \\\"occupation\\\"}, \\\"operator\\\": \\\"eq\\\", \\\"value\\\": \\\"teacher\\\"}, {\\\"field\\\": {\\\"source\\\": \\\"demographic\\\", \\\"key\\\": \\\"country\\\"}, \\\"operator\\\": \\\"eq\\\", \\\"value\\\": \\\"Norway\\\"} ]} ] }, \\\"pagination\\\": {\\\"limit\\\": 25} } ## Testing whether an attribute is set is_not_null matches people who have a value for an attribute, and is_null matches people who do not. Reach for these rather than comparing against an empty string: an attribute nobody filled in holds no value at all, and it satisfies no ordinary comparison, not even a negated one. ## Limits, and how a rule is refused A rule may nest groups at most 2 levels deep, hold at most 15 conditions in any one group, and 25 in total. Both refusals are a 422 carrying an error_kind, and they have different fixes: - search_rule_too_complex: past one of those caps. The detail names the offending count and the limit. Combining values with in costs one condition instead of one per value, and is the usual fix. - search_rule_invalid: the tree is malformed, or it names an attribute, source or operator this API does not publish. The detail names the offender, and GET .../people/schema is the vocabulary it was checked against. A malformed request BODY (rather than a bad rule) is the ordinary validation 422 with the field-level envelope, which is why this operation's 422 documents either shape. ## Saved segments Segments live in the ish app and are not exposed here. A segment IS a rule, so the way to use one is to send its rule as the rule on this request: that is how the ish console itself applies them.\",\"url\":\"https://docs.ishlabs.io/api/reference/people/search-people\",\"mainEntityOfPage\":{\"@id\":\"https://docs.ishlabs.io/api/reference/people/search-people#webpage\"},\"dateModified\":\"2026-10-08T15:42:21.354Z\",\"publisher\":{\"@id\":\"https://docs.ishlabs.io/#organization\"},\"isPartOf\":{\"@id\":\"https://docs.ishlabs.io#website\"}}]}\u003c/script>\u003cscript data-mint-head type=\"application/ld+json\">{\"@context\":\"https://schema.org\",\"@type\":\"WebSite\",\"name\":\"ish\",\"creator\":{\"@type\":\"Organization\",\"name\":\"Mintlify\",\"url\":\"https://mintlify.com\"}}\u003c/script>","siteName":"ish","nav":{"global":{"anchors":[{"anchor":"GitHub","icon":"github","href":"https://github.com/ishlabs"},{"anchor":"ishlabs.io","icon":"globe","href":"https://ishlabs.io"}]},"tabs":[{"tab":"Guides","pages":[{"title":"Guides","href":""}]},{"tab":"CLI Reference","pages":[{"title":"CLI Reference","href":"/cli/overview"}]},{"tab":"MCP Reference","pages":[{"title":"MCP Reference","href":"/mcp/overview"}]},{"tab":"API","groups":[{"group":"Get started","pages":[{"title":"The ish API","mode":"explanation","href":"/api/overview"},{"title":"Quickstart","mode":"tutorial","href":"/api/quickstart"},{"title":"Authentication","mode":"how-to","href":"/api/authentication"}]},{"group":"Core concepts","pages":[{"title":"Sessions and turns","mode":"explanation","href":"/api/concepts/sessions-and-turns"},{"title":"Observations","mode":"explanation","href":"/api/concepts/observations"},{"title":"The decide-only loop","mode":"explanation","href":"/api/concepts/decide-only-loop"},{"title":"Intent and resolution","mode":"explanation","href":"/api/concepts/intent-and-resolution"},{"title":"People","mode":"explanation","href":"/api/concepts/people"}]},{"group":"Guides","pages":[{"title":"Run the session loop","mode":"how-to","href":"/api/guides/session-loop"},{"title":"Author your environment","mode":"how-to","href":"/api/guides/environment-authoring"},{"title":"Score outcomes","mode":"how-to","href":"/api/guides/scoring-outcomes"},{"title":"Search people","mode":"how-to","href":"/api/guides/people-search"}]},{"group":"API reference","pages":[{"title":"API reference","mode":"reference","href":"/api/reference/introduction"},{"title":"Errors","mode":"reference","href":"/api/errors"},{"title":"Create Session","deprecated":null,"version":null,"openapi":"/api/openapi.public.json post /api/v1/workspaces/{workspace_id}/sessions","href":"/api/reference/sessions/create-session"},{"title":"List Sessions","deprecated":null,"version":null,"openapi":"/api/openapi.public.json get /api/v1/workspaces/{workspace_id}/sessions","href":"/api/reference/sessions/list-sessions"},{"title":"Submit Turn","deprecated":null,"version":null,"openapi":"/api/openapi.public.json post /api/v1/sessions/{session_id}/turns","href":"/api/reference/sessions/submit-turn"},{"title":"Get Session","deprecated":null,"version":null,"openapi":"/api/openapi.public.json get /api/v1/sessions/{session_id}","href":"/api/reference/sessions/get-session"},{"title":"Close Session","deprecated":null,"version":null,"openapi":"/api/openapi.public.json post /api/v1/sessions/{session_id}/close","href":"/api/reference/sessions/close-session"},{"title":"Create Environment","deprecated":null,"version":null,"openapi":"/api/openapi.public.json post /api/v1/workspaces/{workspace_id}/environments","href":"/api/reference/environments/create-environment"},{"title":"List Environments","deprecated":null,"version":null,"openapi":"/api/openapi.public.json get /api/v1/workspaces/{workspace_id}/environments","href":"/api/reference/environments/list-environments"},{"title":"Get Environment","deprecated":null,"version":null,"openapi":"/api/openapi.public.json get /api/v1/environments/{environment_id}","href":"/api/reference/environments/get-environment"},{"title":"Update Environment","deprecated":null,"version":null,"openapi":"/api/openapi.public.json patch /api/v1/environments/{environment_id}","href":"/api/reference/environments/update-environment"},{"title":"Delete Environment","deprecated":null,"version":null,"openapi":"/api/openapi.public.json delete /api/v1/environments/{environment_id}","href":"/api/reference/environments/delete-environment"},{"title":"Create Environment Version","deprecated":null,"version":null,"openapi":"/api/openapi.public.json post /api/v1/environments/{environment_id}/versions","href":"/api/reference/environments/create-environment-version"},{"title":"List Environment Versions","deprecated":null,"version":null,"openapi":"/api/openapi.public.json get /api/v1/environments/{environment_id}/versions","href":"/api/reference/environments/list-environment-versions"},{"title":"Get Environment Version","deprecated":null,"version":null,"openapi":"/api/openapi.public.json get /api/v1/environment-versions/{version_id}","href":"/api/reference/environments/get-environment-version"},{"title":"Update Environment Version","deprecated":null,"version":null,"openapi":"/api/openapi.public.json patch /api/v1/environment-versions/{version_id}","href":"/api/reference/environments/update-environment-version"},{"title":"Delete Environment Version","deprecated":null,"version":null,"openapi":"/api/openapi.public.json delete /api/v1/environment-versions/{version_id}","href":"/api/reference/environments/delete-environment-version"},{"title":"Set Default Environment Version","deprecated":null,"version":null,"openapi":"/api/openapi.public.json post /api/v1/environment-versions/{version_id}/set-default","href":"/api/reference/environments/set-default-environment-version"},{"title":"Create Task","deprecated":null,"version":null,"openapi":"/api/openapi.public.json post /api/v1/workspaces/{workspace_id}/tasks","href":"/api/reference/tasks/create-task"},{"title":"List Tasks","deprecated":null,"version":null,"openapi":"/api/openapi.public.json get /api/v1/workspaces/{workspace_id}/tasks","href":"/api/reference/tasks/list-tasks"},{"title":"Get Task","deprecated":null,"version":null,"openapi":"/api/openapi.public.json get /api/v1/tasks/{task_id}","href":"/api/reference/tasks/get-task"},{"title":"Update Task","deprecated":null,"version":null,"openapi":"/api/openapi.public.json patch /api/v1/tasks/{task_id}","href":"/api/reference/tasks/update-task"},{"title":"Delete Task","deprecated":null,"version":null,"openapi":"/api/openapi.public.json delete /api/v1/tasks/{task_id}","href":"/api/reference/tasks/delete-task"},{"title":"List People","description":"List the people you can open a session for, newest first.\n\nTwo kinds of person are reachable: the ones your workspace owns, and the\nones published in the shared ish library. Both are usable in a session, and\neach row's `owner` says which it is. People that other workspaces have\npublished are deliberately NOT listed: you could not open a session for\nthem, and listing what you cannot use is worse than not listing it.\n\nKeyset-paginated: page forward with `after` set to the previous response's\n`next_cursor`, and stop when `has_more` is false. For anything beyond a name\nmatch, use the search endpoint.","deprecated":null,"version":null,"openapi":"/api/openapi.public.json get /api/v1/workspaces/{workspace_id}/people","href":"/api/reference/people/list-people"},{"title":"Search People","deprecated":null,"version":null,"openapi":"/api/openapi.public.json post /api/v1/workspaces/{workspace_id}/people/search","href":"/api/reference/people/search-people"},{"title":"Get Person","description":"Fetch one person by id.\n\nThe read names a workspace because the pool does. Alongside the people your\nworkspace owns, you can read the ones published in the shared ish library,\nand a library person belongs to no workspace of their own. Naming the\nworkspace you are asking as is what lets the same library person be readable\nthrough any workspace you belong to, so this read is workspace-scoped where\na session, an environment or a task is not.\n\nReachability is the same rule the list uses, so a person this workspace can\nneither own nor run answers `404` with `error_kind` `person_not_found`,\nidentical to an id that does not exist. That is deliberate: a\ndistinguishable answer would let anyone test which ids are real.","deprecated":null,"version":null,"openapi":"/api/openapi.public.json get /api/v1/workspaces/{workspace_id}/people/{person_id}","href":"/api/reference/people/get-person"},{"title":"Get People Counts","deprecated":null,"version":null,"openapi":"/api/openapi.public.json get /api/v1/workspaces/{workspace_id}/people/counts","href":"/api/reference/people/get-people-counts"},{"title":"Get People Schema","deprecated":null,"version":null,"openapi":"/api/openapi.public.json get /api/v1/workspaces/{workspace_id}/people/schema","href":"/api/reference/people/get-people-schema"}]},{"group":"Versioning and changes","pages":[{"title":"Versioning and deprecation","mode":"reference","href":"/api/versioning"},{"title":"Changelog","mode":"reference","href":"/api/changelog"}]}]},{"tab":"Help","pages":[{"title":"Help","href":"/help/troubleshooting"}]}]},"basePath":"","title":"Search People - ish","buildId":"dpl_42LwxxU1kGN114H4XzwGYXa9ZDah","deploymentId":"dpl_42LwxxU1kGN114H4XzwGYXa9ZDah","dynamics":["c2aa737661","2b790eda92","b0f84f53ff","a9bb46feb3"],"chunks":["OpenApiReferenceProvider-C-hEh3I2.js","utils-CnF4QiUD.js","cloneDeep-izs3Hzxb.js","_Uint8Array-BVIqJ90l.js","isObjectLike-C8vmzPEN.js","isArray-Dcu1dQ5t.js","utils-C7PVNbel.js","toString-BX-iyh8G.js","isSymbol-CSH9U2Gm.js","addUniqueKeysToSchema-8ytevL2A.js","snippetPresets-BT1alx3v.js","style-to-object-BY3JEAdk.js","v4-DIgz8zy6.js","conditional-requirements-CFM0id0Q.js","ApiExamples-BLXC0i_W.js","isEqual-BfaiBbcl.js","usePlaygroundInputsStore-CyLIGI9_.js","shallow-DC0lGVIW.js","getApiPlaygroundDisplay-CgDQ85tN.js","CodeSnippet-6-I-Gpv9.js","CodeSnippets-BAk1kDdu.js","Page-C945cI-W.js","getPastedJson-B276RuWN.js","icon-BqP8etTm.js","MethodPill-DM6sbxG1.js","DuplicateIcon-PyJglOaE.js","createIcon-CMeOMAc_.js","DynamicMarkdown-BoyYAA8K.js","SectionHeading-DAYv3gvZ.js","axios-vUo_bRtp.js","Markdown-BhTTmazV.js","clsx-CR-RHrVC.js","lib-DuNMoZ05.js","lib-B8HbPgcC.js","html-void-elements-mCSPHezU.js","dist-CBUH0-zX.js","katex-YMM-FMeD.js","marked.esm-CZWythHk.js","AssistantPageLink-BmARFYNC.js"]}