Segments
Create and manage audience segments with dynamic filter criteria for targeted campaigns
Segments let you group contacts by shared characteristics using filter rules. Dynamic segments automatically recalculate membership as contact data changes.
Authentication
The segment CRUD endpoints use session (cookie-based) authentication and are intended for dashboard use — they do not accept API keys. The read-only members endpoint is the exception: it is an API-key route. Base URL: https://api.misar.io/mail.
Endpoints
| Method | Path | Auth | Description |
|---|---|---|---|
GET | /api/segments | session | List segments |
POST | /api/segments | session | Create segment |
GET | /api/segments/:id | session | Get segment |
PATCH | /api/segments/:id | session | Update segment |
DELETE | /api/segments/:id | session | Delete segment |
POST | /api/segments/:id/preview | session | Preview matching contacts |
POST | /api/segments/:id/refresh | session | Recalculate membership |
GET | /v1/segments/:id/members | API key | List member contact IDs |
Filter criteria
Each segment uses a filter_criteria object with a top-level operator (AND or OR) and an array of rules (1–50). A rule is either a leaf condition (field, operator, value) or a nested group (operator, rules).
{
"operator": "AND",
"rules": [
{ "field": "status", "operator": "equals", "value": "subscribed" },
{ "field": "created_at", "operator": "after", "value": "2026-01-01" },
{ "field": "tags", "operator": "contains", "value": "early-adopter" }
]
}Supported rule operators:
| Operator | Description |
|---|---|
equals / not_equals | Exact match |
contains / not_contains | Substring or array membership |
starts_with / ends_with | String prefix/suffix |
greater_than / less_than | Numeric or date comparison |
before / after | Date comparison |
is_empty / is_not_empty | Null/blank check |
in / not_in | Match against a list of values |
List segments
/mail/api/segmentsList segments with pagination. The response merges your MisarMail segments with any audience segments owned on the central misar.io Contacts platform.
Query parameters
pageintegerquerydefault: 1Page number.
limitintegerquerydefault: 20Results per page (max 100).
Response fields
successbooleantrue when the request succeeded.
dataArray<Segment>The page of segments. Each includes id, name, description, segment_type, contact_count, last_calculated_at, filter_criteria, created_at, and updated_at.
paginationobjectpage, limit, total, and totalPages.
curl "https://api.misar.io/mail/api/segments?page=1&limit=20" \
-H "Cookie: session=..."{
"success": true,
"data": [
{
"id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"name": "Active subscribers — Q1 2026",
"description": "Subscribed after Jan 1 with early-adopter tag",
"segment_type": "dynamic",
"contact_count": 1842,
"last_calculated_at": "2026-05-27T10:00:00Z",
"filter_criteria": { "operator": "AND", "rules": [] },
"created_at": "2026-03-15T08:30:00Z",
"updated_at": "2026-05-27T10:00:00Z"
}
],
"pagination": { "page": 1, "limit": 20, "total": 7, "totalPages": 1 }
}Create a segment
/mail/api/segmentsCreate a segment. The segment is evaluated immediately on creation — contact_count and last_calculated_at are populated in the response.
Request body
namestringbodyrequired1–200 characters.
descriptionstringbodyMax 1000 characters.
segment_typedynamic | staticbodyrequiredDynamic re-evaluates on refresh; static is manually managed.
filter_criteriaobjectbodyrequired{ operator, rules }.
Response fields
successbooleantrue when the segment was created.
dataobjectThe created segment, including id, name, segment_type, filter_criteria, contact_count, last_calculated_at, and created_at.
curl -X POST https://api.misar.io/mail/api/segments \
-H "Cookie: session=..." \
-H "Content-Type: application/json" \
-d '{
"name": "Active subscribers — Q1 2026",
"description": "Subscribed after Jan 1 with early-adopter tag",
"segment_type": "dynamic",
"filter_criteria": {
"operator": "AND",
"rules": [
{ "field": "status", "operator": "equals", "value": "subscribed" },
{ "field": "created_at", "operator": "after", "value": "2026-01-01" },
{ "field": "tags", "operator": "contains", "value": "early-adopter" }
]
}
}'{
"success": true,
"data": {
"id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"name": "Active subscribers — Q1 2026",
"segment_type": "dynamic",
"filter_criteria": { "operator": "AND", "rules": [] },
"contact_count": 1842,
"last_calculated_at": "2026-05-27T10:01:44Z",
"created_at": "2026-05-27T10:01:44Z"
}
}Get a segment
/mail/api/segments/:idReturns the full segment object plus membership_count (the live count of member rows, which may differ from the cached contact_count between refreshes).
Path parameters
idstringpathrequiredID of the segment to retrieve.
Response fields
successbooleantrue when the request succeeded.
dataobjectThe full segment object, including filter_criteria, contact_count, and membership_count.
curl https://api.misar.io/mail/api/segments/a1b2c3d4-e5f6-7890-abcd-ef1234567890 \
-H "Cookie: session=..."Update a segment
/mail/api/segments/:idSend only the fields to change (at least one is required). Updating filter_criteria triggers an immediate re-evaluation. segment_type cannot be changed after creation.
Path parameters
idstringpathrequiredID of the segment to update.
Request body
namestringbody1–200 characters.
descriptionstringbodyMax 1000 characters (nullable).
filter_criteriaobjectbody{ operator, rules }. Updating this triggers an immediate re-evaluation.
curl -X PATCH https://api.misar.io/mail/api/segments/a1b2c3d4-e5f6-7890-abcd-ef1234567890 \
-H "Cookie: session=..." \
-H "Content-Type: application/json" \
-d '{ "name": "Active subscribers — updated" }'Delete a segment
/mail/api/segments/:idPermanently delete a segment and its membership rows. Deleting a segment does not delete the contacts in it.
Path parameters
idstringpathrequiredID of the segment to delete.
Response fields
successbooleantrue when the segment was deleted.
{ "success": true }Preview segment contacts
/mail/api/segments/:id/previewEvaluate a filter_criteria object and return the total match count plus a small contact sample, without persisting anything. The :id in the path is ignored — pass new when previewing criteria for a segment that does not exist yet.
Path parameters
idstringpathrequiredSegment ID, or new for an unsaved segment.
Request body
filter_criteriaobjectbodyrequired{ operator, rules } to evaluate.
Response fields
successbooleantrue when the request succeeded.
dataobjectContains count (total matching contacts) and sampleContacts (up to 5 matching contacts, each with id, email, first_name, last_name, status, engagement_tier).
curl -X POST https://api.misar.io/mail/api/segments/new/preview \
-H "Cookie: session=..." \
-H "Content-Type: application/json" \
-d '{ "filter_criteria": { "operator": "AND", "rules": [ { "field": "status", "operator": "equals", "value": "subscribed" } ] } }'{
"success": true,
"data": {
"count": 1842,
"sampleContacts": [
{
"id": "c1a2...",
"email": "ada@example.com",
"first_name": "Ada",
"last_name": "Lovelace",
"status": "subscribed",
"engagement_tier": "high"
}
]
}
}Refresh a segment
/mail/api/segments/:id/refreshRecalculates segment membership against the latest contact data and returns the updated contact_count.
Path parameters
idstringpathrequiredID of the segment to refresh.
Response fields
successbooleantrue when the recalculation completed.
dataobjectContains segment_id, the updated contact_count, and last_calculated_at.
{
"success": true,
"data": {
"segment_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"contact_count": 1901,
"last_calculated_at": "2026-05-27T11:00:00Z"
}
}List segment members
/mail/v1/segments/:id/membersRead-only, paginated list of the contact IDs that are members of a segment. Unlike the CRUD endpoints above, this route is authenticated with an API key (used by other Misar products to build recipient lists without querying the shared database directly).
Authentication: Authorization: Bearer msk_... with the read, segments, or contacts scope.
Path parameters
idstringpathrequiredUUID of the segment.
Query parameters
pageintegerquerydefault: 1Page number.
limitintegerquerydefault: 100Results per page (max 500).
Response fields
successbooleantrue when the request succeeded.
dataobjectContains segment_id and contact_ids (array of contact UUIDs).
paginationobjectpage, limit, total, and totalPages.
curl "https://api.misar.io/mail/v1/segments/a1b2c3d4-e5f6-7890-abcd-ef1234567890/members?page=1&limit=100" \
-H "Authorization: Bearer msk_..."{
"success": true,
"data": {
"segment_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"contact_ids": ["c1a2...", "c3b4..."]
},
"pagination": { "page": 1, "limit": 100, "total": 1842, "totalPages": 19 }
}Status codes
| Code | Meaning |
|---|---|
200 | Request succeeded |
201 | Segment created |
400 | Validation failed (invalid filter criteria or body) |
401 | Not authenticated |
403 | API key missing the required scope (members endpoint) |
404 | Segment not found |
422 | Refresh requested for a segment with no filter criteria |
429 | Rate limit exceeded |