Segments
A segment is a saved audience filter the project keeps by name: how to create one, read it back, understand its cached size, scroll its contacts, reference it from another filter, and audit where it is actually used.
A filter you post to /audience/search or /audience/count lives for one request. Give it a name and the project keeps it: that is a segment. A campaign can target it, an automation can enroll from it, another filter can reference it, and you can ask for its current size whenever you want.
Saving a filter
Save an audience filter as a named segment the project keeps.
{
"name": "Recent Yahoo contacts",
"description": "Contacts with a Yahoo email imported in the last 90 days.",
"queryFilter": {
"version": "0.0.1",
"root": {
"type": "group",
"join": "and",
"children": [
{
"type": "attribute_condition",
"key": "_email",
"operator": "contains",
"values": ["yahoo"]
},
{
"type": "attribute_condition",
"key": "_date_imported",
"operator": "range-date-relative",
"values": {
"lowerOffset": -90,
"lowerOffsetPeriod": "day",
"upperOffset": 0,
"upperOffsetPeriod": "day"
}
}
]
}
}
}name (the label the segment carries in the dashboard, max 50 characters) and queryFilter are required; description (max 256 characters) is optional. The response returns the stored segment.
queryFilter takes exactly the audience query filter grammar and is validated the same way: a root group whose children are attribute conditions, event groups or segment memberships. An invalid filter is refused with a 422 naming the offending node, and nothing is saved.
Saving needs PROJECT_SEGMENT_WRITE. It is a scope of its own, so a token can be allowed to keep segments without being given write access to the audience. Reading segments back takes PROJECT_AUDIENCE_READ instead. See Tokens and scopes.
Reading segments back
List the project's segments, with query-string filtering, sorting and pagination.
One segment, including its stored filter.
Only the dynamic segments that take no parameter.
The list endpoint accepts the generic query filter conventions: field_operator=value for filtering (name_eq=MySegment, type_eq=static), _sort=field:direction for ordering, and _start plus _limit for pagination. When you pass _limit you must also pass _start.
Dynamic segments and their parameter
Some segments are dynamic: they carry a parameter that is supplied when the segment is used, so one definition covers a family of audiences. Pass it as the parameter query argument, pipe-separated for several values (parameter=val1|val2), both when viewing the segment and when scrolling it.
The size on a segment is cached
Every segment view and list row carries a contacts object with the segment's size and the age of that figure.
totalContacts repeats the same number for older clients. Prefer contacts, which carries the age: a bare total invites reading a cached number as a live one. When you need a number you can act on, count the segment's filter through /audience/count.
Working with a segment's contacts
Cursor-scroll the contacts of one segment.
The segment's own filter is merged into whatever you post, so a body with a root filters within the segment rather than replacing it. Everything else behaves like /audience/scroll: PROJECT_AUDIENCE_LIST, up to 100 contacts per page, a cursor that expires after one minute of inactivity, and contact fields redacted according to plan and scopes.
To reference a segment from another filter instead of reading its rows, use a segment_condition with the in-segment or in-segment-not operator. That is how a filter says "these people, but not the ones already in the VIP segment". The grammar is on the query filter page.
Finding the segments nobody uses
Segments accumulate. GET /project/{project}/segment/usage returns, in one request, where each one is actually referenced.
Campaigns that have targeted each segment and automations that enroll from it.
Per segment it reports campaigns, lastTargetedAt, automations and activeAutomations, plus a computedAt for the whole map, which is aggregated per project and cached ten minutes.
The interesting part is what it leaves out. Only segments with at least one reference are returned, so a segment that appears in the list endpoint and not here is an orphan, and that absence is the point: it makes an audit possible in one request instead of one per segment. Combined with the cached size on each list row, two calls find the orphaned, the empty and the stale.
A segment kept alive only through automations that are all inactive is effectively unused too, which is why activeAutomations is reported separately. Flows carry no segment reference and are deliberately not counted here.
What's next
- Query filter: the grammar a segment stores.
- Counting and retrieval: getting a live number, and reading contacts out.
- Campaign audience targeting: pointing a campaign at a segment or at a filter.