Segments
Count who an unsaved filter matches, save it as a reusable segment, and list every segment with its live count, the same dynamic filters the Signups bar uses.
Segments are the dynamic filters behind the segment bar on Signups, saved as a
{ match, conditions } rules tree, evaluated live against the current audience (never a stale
cached number). The API speaks the identical grammar the dashboard's segment builder writes.
Scopes#
| Operation | Scope |
|---|---|
| List, retrieve, preview | segments:read |
| Create | segments:write |
List segments#
GET /v1/segments
Every segment in a project, both the built-in ones (Everyone, Verified, Waiting for verification, Unsubscribed, Can't email, Subscribed and the rest) and your own, each with its live
matching count. There is no pagination: a project holds at most a few dozen, so this answers the
whole set in one call. Takes project (required).
Retrieve a segment#
GET /v1/segments/{segment}
{segment} is a seg_… handle. Returns the segment object with count
computed fresh, not the stale figure a dashboard cache might show for a moment.
Count who an unsaved filter matches#
POST /v1/segments/preview
The live count for a rules tree that is not saved anywhere. Use it before POST /segments to
sanity-check a filter, or before a tag apply call with limit to see how big
a wave you are about to touch.
| Parameter | Type | Required | Description |
|---|---|---|---|
project |
string | Yes | A prj_ handle. |
rules |
object | No | The condition tree, below. Omitted or empty counts everyone. |
Returns { "object": "segment_preview", "count": <integer> }.
Create a segment#
POST /v1/segments
Saves a rules tree as a named, reusable segment. Requires name (up to 120 characters) and
rules; description, icon, color and pinned are optional. Returns 201 with the
segment object.
Saving a segment of your own is available on Launch and Grow. On a plan without it this is a 422
naming the entitlement in message, not a silent no-op, check the response rather than assuming
the segment was created.
The rules tree#
{
"match": "and",
"conditions": [
{ "field": "is_referrer", "operator": "is_true" },
{ "field": "status", "operator": "eq", "value": "subscribed" }
]
}
match is and or or. Each entry in conditions is either a nested group (the same
{ match, conditions } shape, up to 5 levels deep) or a leaf: { field, operator, value }. Both
POST /segments and POST /segments/preview validate the tree and refuse with a 422 on an
unknown field, an operator illegal for its field, or a malformed value, a typo never silently
widens the match into something you didn't ask for.
| Field(s) | Operators | value |
|---|---|---|
status, unsubscribed_by, consent, trust_tier, deliverability, stage, invite_state, identifier_type, first_source, country, device, browser, os, intent_cluster |
eq, neq, in, not_in |
string, or a string array for in/not_in |
referral_count, quality_score |
gt, gte, lt, lte, between |
number, or [min, max] for between |
created_at, verified_at, consented_at |
the same comparisons, plus within_last_days, exists, not_exists |
an ISO 8601 date; an integer for within_last_days; omit for exists and not_exists |
submission_count |
eq, gt, gte, lt, lte |
number |
tag |
in, not_in, exists |
an array of tag_… handles, from GET /v1/tags; omit for exists |
received_broadcast |
in, not_in |
an array of 1-50 bcd_… broadcast handles, all from this project |
is_referrer, is_referred, awaiting_verification |
is_true, is_false |
omit |
utm_source, utm_medium, utm_campaign |
eq, neq, in, contains, exists |
string, string array, or omit for exists |
attribute |
eq, neq, contains, exists, not_exists, in |
needs key alongside field/operator/value |
The status values are pending (shown as Not subscribed), subscribed, unsubscribed, bounced and blocked. People who joined but have not verified their email are subscribed with verified_at not set. awaiting_verification with is_true is the people sent a link to verify their email who have not clicked it yet (an expired link included): with status subscribed, it is the built-in Waiting for verification segment, and the people a broadcast's recipients: unverified reaches. verified_at with not_exists is wider: it also matches people who were never asked to verify. For a few minutes after the update that added awaiting_verification, POST /segments refuses it with a 422; POST /segments/preview takes it at once. A rule that says verified, the old name of subscribed, is still accepted for now and is read as subscribed.
received_broadcast also takes an optional days (integer, 1 to 3650): "sent at least this many
days ago." Combine it with in or not_in to build waves, for example "received the launch email
at least 3 days ago":
{
"match": "and",
"conditions": [
{ "field": "received_broadcast", "operator": "in", "value": ["bcd_4kq3mxrz9dnp"], "days": 3 }
]
}
The segment object#
{
"object": "segment",
"id": "seg_7qk2mn4pr8vx",
"project": "prj_7Qk2mN4pR8",
"name": "Engaged referrers",
"description": null,
"type": "dynamic",
"is_system": false,
"pinned": false,
"icon": null,
"color": null,
"rules": { "match": "and", "conditions": [] },
"count": 214,
"created_at": "2026-09-24T10:02:11+00:00",
"url": "/v1/segments/seg_7qk2mn4pr8vx"
}
count is null only when it genuinely could not be computed, never a false zero standing in for
"no matches."
Next#
Common questions
What scope does segments need?
segments:read for listing, retrieving and previewing (counting who matches a filter is a read, nothing is saved). segments:write to save a new one.
Can I filter on a custom attribute my form captured?
Yes, with the attribute field: { "field": "attribute", "key": "company", "operator": "contains", "value": "Acme" }. The key is your form field's key, whitelisted to letters, digits, underscore and dot.
Do tag and received_broadcast conditions take a handle, like everything else in the API?
Yes. tag's value is an array of tag_… handles from GET /v1/tags, and received_broadcast's value is an array of bcd_… broadcast handles. A segment you read back carries handles too, never the internal ids the compiler actually runs against.
Does previewing or saving a segment ever reveal deliverability verdicts I have not paid for?
No. A deliverability condition only ever counts contacts whose verdict the workspace has already revealed with a credit, the same gate every other surface in the product reads through.
What counts as "received" a broadcast?
A send that was actually handed to the provider and not suppressed, for example by an unsubscribe that landed before the send ran. A broadcast still mid-send counts too, since a second broadcast going out the same afternoon must not also mail that person. People a canceled broadcast never reached do not count.