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.

typeKeysMatches
groupop (and, or), childrenCombines conditions.
fieldfield, op, valuefield is email, first_name, last_name or fields.<key>. Ops: eq, ne, contains, starts_with, gt, gte, lt, lte, is_set, is_not_set.
tagtag, has (default true)Has, or with has false does not have, the tag.
listlist_id, member (default true)Is, or is not, on the list.
statusis: string[]Status is one of active, unsubscribed, bounced, complained.
engagementaction, within_days, min_count (default 1), negateaction is sent, opened, clicked or engaged (opened or clicked). With negate: fewer than min_count.
eventname, within_days, min_count, negateThe contact tracked an event that often.
datefield, op, days or datefield 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

RequestBody or queryReturns
GET /v1/segmentsnoneBuilt in and saved segments.
POST /v1/segmentsname, description, filter201 and the segment.
GET /v1/segments/{id}noneThe segment with last_count.
PATCH /v1/segments/{id}name, description, filterThe segment.
DELETE /v1/segments/{id}none204.
GET /v1/segments/{id}/countnone{ "count": n }, live.
GET /v1/segments/{id}/contactslimit 1..100 (default 25), afterdata and next.
POST /v1/segments/previewfilter, 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

CodeStatusMeaning and fix
invalid_filter400The tree is malformed or over a limit. The message names the problem.
invalid_segment_name400Give the segment a name.
segment_name_taken409Pick another name.
segment_not_found404List segments with GET /v1/segments.
segment_limit402Delete segments you no longer use (200 per workspace).
segment_too_slow400The filter takes too long to evaluate. Narrow it.
builtin_segment_readonly403Quick filters cannot be changed. Save a copy as a new segment.

Something unclear or wrong? The API answers every error with a fix, and so should these docs. Back to runearc.com