Query persons
Person-grain twin of POST /observe/companies/query: compiles the filter/sort/columns into parameterized read-only SQL (ackdb_readonly role) and returns a page of person rows with pagination metadata. ids selects by person_id. Merged (tombstoned) persons never surface - the compiler's base gate is status = 'active'; the default sort is newest human first. Two filter node kinds are rejected with 400 on this grain: TRAIT conditions (a human has keys and events, not traits - filter their companies/contacts instead, or use an idl__ key column) and raw EVENT conditions (use the evc__/emf__ columns, which carry the STORED source-prefixed event type). COMPANY filter (#334): { "type": "attribute", "field": "entity_id", "operator": "eq"|"in"|"is_null"|"is_not_null", "value": … } answers "who works at X?" - it compiles to an EXISTS over the person's ACTIVE affiliation edges, so someone who LEFT the company is NOT returned (they keep a former edge). It is FILTER-ONLY: a human has 1..N companies, so entity_id is not a column - project companies (a string_array of names) to display them, and note it is absent from GET /observe/persons/fields for that reason. neq and the ordered comparators are rejected rather than guessed at (on a 1..N edge set, "not Acme" is ambiguous). If the count query is rejected or times out, total is clamped and pagination.totalIsLowerBound is set to true.
Request
- Base URLhttp://localhost:3009
- AuthHTTP bearer
Request body
Example request
{
"filter": {
"children": [
{
"traitKey": "hubspot_lifecycle_stage"
}
]
},
"sort": [
{
"field": "event_count"
}
],
"columns": [
{
"field": "name",
"frozen": true,
"width": 200
}
],
"limit": 50
}Response
A page of person rows.
Example response
{
"pagination": {
"total": 150,
"limit": 50,
"totalIsLowerBound": true
}
}Changes
No recorded changes to this operation across all 1 revision of this API.