Segments
A segment is a saved filter over your contacts. It is evaluated live, so membership always reflects now. Use one as a campaign audience.
The filter
A filter is a tree. A group combines children with and or or; every other node is one condition. Depth is
limited to 4, a filter to 50 conditions, text values to 256 characters and day counts to 3650.
| type | Keys | Matches |
|---|---|---|
| group | op (and, or), children | Combines conditions. |
| field | field, op, value | field is email, first_name, last_name or fields.<key>. Ops: eq, ne, contains, starts_with, gt, gte, lt, lte, is_set, is_not_set. |
| tag | tag, has (default true) | Has, or with has false does not have, the tag. |
| list | list_id, member (default true) | Is, or is not, on the list. |
| status | is: string[] | Status is one of active, unsubscribed, bounced, complained. |
| engagement | action, within_days, min_count (default 1), negate | action is sent, opened, clicked or engaged (opened or clicked). With negate: fewer than min_count. |
| event | name, within_days, min_count, negate | The contact tracked an event that often. |
| date | field, op, days or date | field is created_at, updated_at or a date field. Ops: before, after, within_last_days, older_than_days. |
curl -X POST https://api.runearc.com/v1/segments \
-H "Authorization: Bearer $RUNEARC_API_KEY" \
-H "Content-Type: application/json" \
-d '{ "name": "Active pro, opened lately",
"filter": { "type": "group", "op": "and", "children": [
{ "type": "status", "is": ["active"] },
{ "type": "tag", "tag": "pro" },
{ "type": "engagement", "action": "opened", "within_days": 30 }
] } }'Unknown keys in a condition are refused with invalid_filter, which says which key and which condition.
Built in quick filters
Six read only filters ship with every workspace and appear in GET /v1/segments with builtin: true and ids that
start with builtin_: New subscribers, Engaged, Inactive, Recent clickers, Not mailed recently and
Highly engaged. Changing one gives builtin_segment_readonly.
API
| Request | Body or query | Returns |
|---|---|---|
| GET /v1/segments | none | Built in and saved segments. |
| POST /v1/segments | name, description, filter | 201 and the segment. |
| GET /v1/segments/{id} | none | The segment with last_count. |
| PATCH /v1/segments/{id} | name, description, filter | The segment. |
| DELETE /v1/segments/{id} | none | 204. |
| GET /v1/segments/{id}/count | none | { "count": n }, live. |
| GET /v1/segments/{id}/contacts | limit 1..100 (default 25), after | data and next. |
| POST /v1/segments/preview | filter, limit (default 10) | count and a sample of contacts, without saving. |
A workspace can have 200 saved segments.
CLI and MCP
runearc segments list
runearc segments create "Pro users" --filter @filter.json
runearc segments preview --filter '{"type":"status","is":["active"]}' --limit 10
runearc segments count seg_...
runearc segments delete seg_...MCP tools: list_segments, create_segment, preview_segment and delete_segment.
Errors
| Code | Status | Meaning and fix |
|---|---|---|
| invalid_filter | 400 | The tree is malformed or over a limit. The message names the problem. |
| invalid_segment_name | 400 | Give the segment a name. |
| segment_name_taken | 409 | Pick another name. |
| segment_not_found | 404 | List segments with GET /v1/segments. |
| segment_limit | 402 | Delete segments you no longer use (200 per workspace). |
| segment_too_slow | 400 | The filter takes too long to evaluate. Narrow it. |
| builtin_segment_readonly | 403 | Quick filters cannot be changed. Save a copy as a new segment. |