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 attributesevent— a windowed, frequency-bounded predicate over tracked eventsgroup— 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" } } }
]
}
}
]
}
| Field | Type | Description |
|---|---|---|
op | string | "and" or "or" — how the nodes combine. |
nodes | array | One 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
| Field | Type | Description |
|---|---|---|
name | string | Required. The tracked event name. |
within | string | Recency window, e.g. "30d", "24h", "45m" (whole-unit d/h/m). Omitted = all time — only allowed on plans without a lookback cap. |
frequency | object | { "min": N }, { "max": N }, or both (inclusive bounds on the event count). Default is "at least once". |
where | object | Optional 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
| Parameter | Type | Description |
|---|---|---|
cursor | string | Opaque 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": ""
}
| Field | Type | Description |
|---|---|---|
is_dynamic | boolean | Whether membership is recomputed as events arrive. |
needs_recompute | boolean | The rule changed since the last membership computation. |
count | integer | Number of currently active members. |
rule | object | The stored rule tree; omitted when the segment has no rules. |
next_cursor | string | Empty 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 } } }
]
}
}
| Field | Type | Required | Description |
|---|---|---|---|
name | string | Yes | Segment name (unique per tenant). |
is_dynamic | boolean | No | Defaults to false. Dynamic segments count against your plan's active-dynamic-segment cap. |
rule | object | Yes | The rule tree or simple flat form. |
Response — 201 Created
The created segment, same shape as one entry of GET /api/v1/segments.
Error Codes
| Status | Reason |
|---|---|
| 401 | Missing or invalid bearer token. |
| 403 | FEATURE_NOT_AVAILABLE — the plan's dynamic-segment cap is reached, or dynamic segments are not included. |
| 409 | A segment with that name already exists. |
| 422 | VALIDATION_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
| Status | Reason |
|---|---|
| 401 | Missing or invalid bearer token. |
| 404 | Segment not found. |
| 409 | Another segment already uses that name. |
| 422 | Malformed 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-..."]
}
| Field | Type | Description |
|---|---|---|
estimated_count | integer | Number of subscribers currently matching the rule. |
sample_subscriber_ids | array of strings | Up 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"] }