Segments API — Mimeo docs
Segments API
Full parity with the UI. Segments are addressed by key, not by database id, so a definitions file can name one without knowing anything about your database.
Every endpoint needs a bearer token from Settings → Agents & API.
Endpoints
| Method | Path | What it does |
|---|---|---|
| GET | /api/v1/segments |
Every segment with its live count |
| POST | /api/v1/segments |
Create one |
| GET | /api/v1/segments/:key |
One segment, with rules and where it's used |
| PATCH | /api/v1/segments/:key |
Update it |
| DELETE | /api/v1/segments/:key |
Delete it |
| GET | /api/v1/segments/:key/count |
Just the number |
| GET | /api/v1/segments/:key/members |
The people, paginated |
| POST | /api/v1/segments/preview |
Check and count rules without saving them |
Count and members are separate on purpose. Asking "how many?" shouldn't make you pay for the list, and asking for the list shouldn't hand you forty thousand rows in one response. members is paginated, capped at 500 per page.
Creating a segment
curl -X POST https://your-mimeo.com/api/v1/segments \
-H "Authorization: Bearer $MIMEO_TOKEN" \
-H "Content-Type: application/json" \
-d '{\n "name": "Engaged customers",\n "description": "Bought something and opened recent mail.",\n "rules": {\n "type": "all",\n "conditions": [\
{ "type": "total_spend", "op": "greater", "value": 0 },\
{ "type": "opened_email", "email_id": 12, "within_days": 60 },\
{ "type": "not", "condition": { "type": "suppressed" } }\
]\n }\n }'```
The key is derived from the name (`engaged_customers`) unless you supply one.
## Checking rules before you commit to them
`preview` validates and counts a rule set without creating anything — the API's answer to the editor's live count, and what a definitions-repo diff should call before applying a change.
curl -X POST https://your-mimeo.com/api/v1/segments/preview
-H "Authorization: Bearer $MIMEO_TOKEN"
-H "Content-Type: application/json"
-d '{ "rules": { "type": "has_tag", "tag": "customer" } }'```
{
"count": 412,
"total": 5310,
"exact": true,
"expensive": false,
"validation": { "valid": true, "errors": [], "warnings": [] }
}
exact— the whole rule set resolved in SQL.expensive— it needs a query per candidate person (a code predicate, or an event matched on its details).
Errors name the fix
Invalid rules come back as 422 with messages written to be acted on rather than just reported:
{
"errors": [\
"This rule tests field \"plan_tier\", which is not a defined field. Create it under People → Fields first."\
],
"validation": { "valid": false, "errors": [ … ] }
}
Deleting a segment something still references is refused, with used_by listing what would break.
The rule vocabulary
The same condition types flows and guards use — see the schema reference for the full list. Segments add total_spend, and support within_days on received_email, opened_email and clicked_email.
email compares the person's email address, ignoring case, with equals, starts_with, ends_with or contains — so "everyone at acme.com" is { "type": "email", "op": "ends_with", "value": "@acme.com" }.
in_segment takes a segment key. A reference loop is rejected on save.
subscribed_on compares the date a person joined the list against a value like "2026-06-01", using less (before), greater (after) or equals (on). Both comparisons are strict. Everyone has the date, so this is a single condition with no null case to wrap:
{ "type": "all", "conditions": [\
{ "type": "subscribed_on", "op": "less", "value": "2026-06-01" },\
{ "type": "not", "condition": { "type": "suppressed" } }\
] }
Next: The subscription API →