Skip to main content
A segment is a named audience: a filter over your people, the custom objects related to them, and the events they generated, saved once and reused. Instead of re-describing “premium customers who haven’t paid in 30 days” every time you launch an initiative, you define it as a segment and point a journey’s trigger at it. Segments are how you decide who a conversation reaches. A win-back journey, an NPS follow-up, an onboarding nudge: each one starts from a segment, not from a hand-picked list of people.

Discover what you can filter on

You cannot guess your own attribute names, so start by reading the catalog instead of writing a filter blind:
The response lists everything filterable in your organization, each with the exact attr token to use and the operators valid for it:
  • personAttributes: typed columns on the person (email, status, createdAt) plus every custom attributes.<key> your org has ingested.
  • computedVariables: virtual computed.<key> values (an aggregate or expression over related data) resolved at filter time, with no stored value of their own.
  • customObjectTypes: each type’s own filterable attributes, addressed as object.attributes.<key> once you reach that type through a relationship.
  • reachableObjects: the custom-object types reachable from a person, and every relationship path that gets you there, direct or through one or two intermediate objects.
  • operatorReference: every operator’s expected value shape (scalar, list, date, dateRange, relativeWindow, dateOffset, none), so you don’t have to guess whether an operator wants a string, a list, or a window.
The catalog is generated from the same registry the compiler enforces at save time, so it never lists an attribute or operator combination that would actually be rejected.

Build a filter

A segment’s filter is a FilterExpression: a tree of predicates joined by AND/OR. Each predicate is one of a few kinds: A segment for premium customers who have gone quiet on payments. Note the event predicate: events reach Boom through the API, not through the database sync, which syncs people, custom objects and relationships only. If your payment history arrives by database sync, filter on a custom object’s date attribute with has_relationship instead.
Operators worth knowing:
contains and not_contains accept a single substring or a list. A list means “any of these”: contains matches a row with any needle, not_contains keeps a row with none of them. To exclude several values, pass one not_contains with all of them, not a comma-joined string.

Author a segment end to end

The catalog, validate, preview, create, evaluate, and members endpoints form one loop. An agent (or a script) can walk it without ever opening the dashboard.
1

Read the catalog

GET /api/v1/segments/catalog (segments_catalog). See what’s filterable before writing anything.
2

Validate the filter

POST /api/v1/segments/validate (segments_validate) with a filterExpression. This is a dry-run compile against your live catalog. Nothing is saved; a bad attribute or operator fails here with the exact field to fix.
3

Preview the match count

POST /api/v1/segments/preview (segments_preview) runs the same filter and returns { "count": N }, the number of people it currently matches. No segment is created.
4

Create the segment

POST /api/v1/segments (segments_create) with name, slug, and the filterExpression. Creating a segment compiles and stores the filter, it does not evaluate it: the response comes back with memberCount: 0 regardless of how many people actually match.
5

Evaluate it

POST /api/v1/segments/{slug}/evaluate (segments_evaluate) runs the filter now and writes the membership rows, returning { "entrants", "leavers", "total" }. Nothing is a member until an evaluation runs at least once.
6

Read the members

GET /api/v1/segments/{slug}/members (segments_members_list) lists the active members, newest first: name, phoneNumber, externalId, email, enteredAt. Keyset-paginated with next_cursor, same pattern as every other list endpoint.
PATCH /api/v1/segments/{slug} (segments_update) updates any field except the slug, which is permanent. Changing filterExpression recompiles the filter but does not re-evaluate it, so the member set stays exactly as it was until the next evaluate call.

Keeping a segment fresh

A segment’s membership is a set of rows, not a live query, so it only changes when an evaluation runs. How often that happens is evaluationCadence:
  • REACTIVE_ONLY (the default). The segment re-evaluates the specific people a CDP write touches, usually within seconds of that write, plus a daily backstop sweep to catch anything a reactive update missed. Nothing else triggers it, so an explicit segments_evaluate call is how you force a full refresh.
  • HOURLY or DAILY. A scheduled sweep evaluates the whole segment on that cadence, independent of any particular write. Useful for filters that depend on the passage of time itself, like “hasn’t paid in 30 days,” which can flip with no new data at all.
Whichever cadence you choose, a freshly created or just-edited segment shows a stale or empty member set until the next evaluation actually runs.
Set the cadence explicitly when you create a segment over the API. The default for API-created segments is REACTIVE_ONLY, and this page’s own example is the case it handles worst: “no payment in 30 days” turns true from the passage of time, not from a write, so nothing reactive fires when a customer crosses the line. Ask for HOURLY or DAILY on any filter whose answer changes with the calendar, or evaluate on your own schedule.

How a segment reaches outreach

A segment does not attach to an initiative directly. It becomes the trigger on the journey behind that initiative: the journey’s entry node is configured with triggerType: segment and a segmentId. Once that journey is published, every evaluation that adds someone to the segment enrolls them, carrying along whatever data the segment projects for that person.
Wiring that trigger is an app job today. It needs the segment’s internal id, and this API identifies segments by slug, so set a segment trigger in the Boom app rather than over the API.

Limits and gotchas

segments_evaluate runs synchronously over the API and MCP, unlike the dashboard’s “Evaluate now” button, which queues the evaluation in the background and returns immediately. On a large organization, a synchronous evaluate call can take a while and holds the request open the whole time. If you just need the segment defined and don’t need its membership refreshed right away, skip the evaluate call and let its cadence run it.
  • Create and update never evaluate. memberCount is 0 right after segments_create, and a filter change from segments_update leaves the existing member set untouched until you call segments_evaluate.
  • Weekend freeze. A segment with skipWeekendEvaluation set rejects an explicit evaluate on Saturday or Sunday (in your organization’s timezone) with 400 weekend_evaluation_skipped.
  • Deleting requires organization admin over MCP. segments_delete is a soft delete: it disappears from every list immediately, and its journey triggers are removed so no journey keeps enrolling from it. It is idempotent, { "removed": false } on a segment that is already gone.
  • Pagination. segments_list and segments_members_list are keyset-paginated, defaulting to 100 rows and capped at 1000; loop on next_cursor until it comes back null.
  • Preview returns a count only. It does not return a sample of matching people over the API or MCP, only the total.
  • Slugs are permanent. Pick one deliberately; segments_update cannot rename it.

Customer Data Platform

The people, objects, and events a segment’s filter reads.

Events

How the events an event predicate matches against get recorded.

Journeys

Set a segment as a journey’s trigger to turn membership into outreach.

Use MCP

Author segments conversationally with the same tools documented here.