Segments
A segment is a saved filter, not a saved list.
Membership is recomputed every time you read it. A contact that gains a matching property joins immediately; one that opts out leaves immediately. There is no materialised join table and no scheduled rebuild that can fall behind.
Filter shape
A filter is a tree of groups and conditions:
{
"all": [
{ "field": "unsubscribed", "operator": "is", "value": false },
{ "any": [
{ "field": "property:plan", "operator": "equals", "value": "pro" },
{ "field": "tag:3f2504e0-4f89-41d3-9a0c-0305e82c3301", "operator": "has" }
]}
]
}all is AND, any is OR, and they nest.
Empty groups
An empty all matches everyone; an empty any matches no one. Getting those backwards is the difference between mailing nobody and mailing your entire list.
Fields
| Field | Example operators |
|---|---|
email | equals, contains, ends_with |
unsubscribed | is |
property:<key> | depends on the declared type — equals, greater_than, before, exists |
tag:<uuid> | has, not_has |
Tags are referenced by id, not name. List them with /v1/contact-tags.
Reading the members
curl "http://api.localhost/v1/segments/$SEGMENT_ID/contacts?page=1&per_page=100" \
-H "X-API-Key: $NOTIFYZR_API_KEY"This is the only place a filter turns into rows. Because membership is live, two calls a minute apart can legitimately return different totals.
Deleting
Deleting a segment removes the definition only. Nothing cascades — membership was never stored. A segment that a broadcast references cannot be deleted while that broadcast exists.