Skip to main content

Segments API

Segments are live behavioral audiences: a rule over subscriber attributes and tracked events, evaluated against your subscriber base. A dynamic segment is recomputed as new events arrive; a static segment keeps the membership it had when it was created. Segments can be targeted from notifications, journeys, and in-app experiences.

All segment endpoints are authenticated with a tenant JWT bearer token (Authorization: Bearer ...) — the credential used by dashboard sessions. The publishable SDK key cannot manage segments.

Plan limits apply to segment rules: the maximum event lookback window, the number of event conditions per rule, and the number of active dynamic segments all depend on your plan. Rule-shaped violations return 422 with a message naming the limit; creating a dynamic segment beyond your plan's cap returns 403 FEATURE_NOT_AVAILABLE.


The rule object

A segment's rule is a boolean tree. Each node is exactly one of:

  • attribute — a predicate over subscriber attributes
  • event — a windowed, frequency-bounded predicate over tracked events
  • group — a nested rule set, for mixing AND and OR
{
"op": "and",
"nodes": [
{ "attribute": { "tier": { "$eq": "premium" } } },
{
"event": {
"name": "order_placed",
"within": "30d",
"frequency": { "min": 2 }
}
},
{
"group": {
"op": "or",
"nodes": [
{ "attribute": { "country": { "$in": ["US", "CA"] } } },
{ "attribute": { "locale": { "$eq": "en-GB" } } }
]
}
}
]
}
FieldTypeDescription
opstring"and" or "or" — how the nodes combine.
nodesarrayOne or more nodes; each sets exactly one of group, attribute, event.

Attribute conditions

An attribute node maps an attribute key to an operator object, using the same Mongo-style predicate DSL as audience filters: $eq, $ne, $gt, $gte, $lt, $lte, $in, $nin, $exists.

{ "attribute": { "plan": { "$eq": "pro" } } }

Event conditions

FieldTypeDescription
namestringRequired. The tracked event name.
withinstringRecency window, e.g. "30d", "24h", "45m" (whole-unit d/h/m). Omitted = all time — only allowed on plans without a lookback cap.
frequencyobject{ "min": N }, { "max": N }, or both (inclusive bounds on the event count). Default is "at least once".
whereobjectOptional predicate over the event's properties, same operator DSL as attribute conditions.

Simple flat form

The single-condition form is also accepted anywhere a rule is expected: an optional attribute condition and an optional event condition, combined with AND. At least one of the two is required.

{
"attribute": { "key": "tier", "operator": "eq", "value": "premium" },
"event": { "name": "order_placed", "operator": "gte", "count": 2, "within_days": 30 }
}

attribute.operator is a DSL operator without the $ prefix (eq, in, gte, ...; defaults to eq). event.operator is gte, lte, or eq against count.


GET /api/v1/segments

Lists the tenant's segments (cursor-paginated, up to 100 per page).

Query Parameters

ParameterTypeDescription
cursorstringOpaque cursor from the previous page. Omit for the first page.

Response — 200 OK

{
"segments": [
{
"id": "9f5b2c1e-...",
"name": "Premium repeat buyers",
"is_dynamic": true,
"needs_recompute": false,
"created_at": "2026-07-01T12:00:00Z",
"updated_at": "2026-07-01T12:00:00Z",
"count": 1834,
"rule": { "op": "and", "nodes": [] }
}
],
"next_cursor": ""
}
FieldTypeDescription
is_dynamicbooleanWhether membership is recomputed as events arrive.
needs_recomputebooleanThe rule changed since the last membership computation.
countintegerNumber of currently active members.
ruleobjectThe stored rule tree; omitted when the segment has no rules.
next_cursorstringEmpty when there are no further pages.

POST /api/v1/segments

Creates a segment.

Request Body

{
"name": "Premium repeat buyers",
"is_dynamic": true,
"rule": {
"op": "and",
"nodes": [
{ "attribute": { "tier": { "$eq": "premium" } } },
{ "event": { "name": "order_placed", "within": "30d", "frequency": { "min": 2 } } }
]
}
}
FieldTypeRequiredDescription
namestringYesSegment name (unique per tenant).
is_dynamicbooleanNoDefaults to false. Dynamic segments count against your plan's active-dynamic-segment cap.
ruleobjectYesThe rule tree or simple flat form.

Response — 201 Created

The created segment, same shape as one entry of GET /api/v1/segments.

Error Codes

StatusReason
401Missing or invalid bearer token.
403FEATURE_NOT_AVAILABLE — the plan's dynamic-segment cap is reached, or dynamic segments are not included.
409A segment with that name already exists.
422VALIDATION_ERROR — malformed rule, or the rule exceeds a plan cap (event-condition count, lookback window, all-time window on a capped plan). The message names the specific problem.

PATCH /api/v1/segments/:id

Replaces a segment's name and rule. is_dynamic cannot be changed in place. Rule validation, including plan caps, mirrors create.

Request Body

{
"name": "Premium repeat buyers (90d)",
"rule": {
"op": "and",
"nodes": [
{ "event": { "name": "order_placed", "within": "90d", "frequency": { "min": 2 } } }
]
}
}

Both name and rule are required.

Response — 200 OK

The updated segment.

Error Codes

StatusReason
401Missing or invalid bearer token.
404Segment not found.
409Another segment already uses that name.
422Malformed rule or plan-cap violation.

DELETE /api/v1/segments/:id

Deletes a segment and, by cascade, its memberships.

Response — 204 No Content

404 when the segment does not exist.


POST /api/v1/segments/preview

Evaluates a rule without persisting it and returns a live size estimate. The request body is the rule object itself (tree or simple flat form), not wrapped in an envelope.

Request Body

{
"op": "and",
"nodes": [
{ "event": { "name": "cart_abandoned", "within": "7d" } }
]
}

Response — 200 OK

{
"estimated_count": 412,
"sample_subscriber_ids": ["8a2f6c1e-...", "1b9d4e7a-..."]
}
FieldTypeDescription
estimated_countintegerNumber of subscribers currently matching the rule.
sample_subscriber_idsarray of stringsUp to 10 matching subscriber IDs.

422 on a malformed rule or plan-cap violation.


GET /api/v1/segments/attribute-keys

Returns the tenant's known subscriber-attribute keys (up to 500) — useful for building rule editors and personalization pickers.

Response — 200 OK

{ "keys": ["plan", "country", "tier"] }

GET /api/v1/segments/event-names

Returns the tenant's distinct tracked event names (up to 200) — the autocomplete source for event conditions.

Response — 200 OK

{ "names": ["order_placed", "cart_abandoned", "app_opened"] }