Segments
A segment is a saved filter over one audience. It’s live: membership is computed at read time, never stored, so there is nothing to refresh.
Target a campaign with one, or pass ?segment_id= when listing
contacts.
The Segment object
{
"id": "seg_456m9x4v0dz1",
"object": "segment",
"name": "Pro-plan customers",
"filter": {
"match": "all",
"conditions": [
{ "field": "plan", "op": "equals", "value": "pro" },
{ "field": "company", "op": "is_set" }
]
},
"created_at": "2026-05-01T10:00:00.000Z",
"updated_at": "2026-05-01T10:00:00.000Z"
}The filter contract
filter is the whole contract, and it’s stable.
| Key | Values |
|---|---|
match | "all" or "any". |
conditions | 1 to 10 conditions, each { field, op, value? }. |
field is email, first_name, last_name, or any custom attribute key.
op | Takes value | Notes |
|---|---|---|
equals | Yes | |
not_equals | Yes | |
contains | Yes | Substring. |
not_contains | Yes | |
is_set | No | Has any non-empty value. |
is_not_set | No | |
greater_than | Yes | Numeric comparison. |
less_than | Yes | Numeric comparison. |
Operators may be added, never removed.
value is always a JSON string, even for greater_than and less_than.
Send "5", never 5: a bare number is 400 invalid_request. The comparison is
still numeric, so "5" and "40" order correctly. A stored value that isn’t a
number doesn’t match.
A missing attribute counts as empty, so plan not_equals pro includes contacts
with no plan at all. Check that before targeting a send.
A filter rejected on write is 400 invalid_request, with param naming the
exact path, such as filter.conditions.0.value. invalid_filter is the read
side: a stored filter no longer parses, so listing its members fails instead
of quietly matching everyone.
List segments
/v1/audiences/{audience_id}/segmentsCreate a segment
/v1/audiences/{audience_id}/segmentscurl -X POST https://go.day3.app/api/v1/audiences/aud_123/segments \
-H "Authorization: Bearer $DAY3_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"name": "Pro customers",
"filter": {
"match": "all",
"conditions": [
{ "field": "plan", "op": "equals", "value": "pro" },
{ "field": "company", "op": "is_set" }
]
}
}'| Field | Type | Required |
|---|---|---|
name | string | Yes |
filter | object | Yes |
Retrieve a segment
/v1/audiences/{audience_id}/segments/{segment_id}Update a segment
/v1/audiences/{audience_id}/segments/{segment_id}name, filter, or both. A new filter replaces the old one whole. No merge.
Delete a segment
/v1/audiences/{audience_id}/segments/{segment_id}Deletes the filter. Contacts are untouched.
List the members of a segment
/v1/audiences/{audience_id}/segments/{segment_id}/contactsCurrent matches as Contact objects,
paginated. Same as listing contacts with
?segment_id=seg_456.
curl "https://go.day3.app/api/v1/audiences/aud_123/segments/seg_456/contacts?limit=100" \
-H "Authorization: Bearer $DAY3_API_KEY"Errors
| Status | Code | Cause |
|---|---|---|
| 400 | invalid_request | The filter failed validation on write. param names the path. |
| 400 | invalid_filter | A stored filter no longer parses, so its members can’t be listed. |