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 → API tokens.
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-instance.com/api/v1/segments \
-H "Authorization: Bearer $MIMEO_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"name": "Engaged customers",
"description": "Bought something and opened recent mail.",
"rules": {
"type": "all",
"conditions": [
{ "type": "total_spend", "op": "greater", "value": 0 },
{ "type": "opened_email", "email_id": 12, "within_days": 60 },
{ "type": "not", "condition": { "type": "suppressed" } }
]
}
}'
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-instance.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 flow API for the full list. Segments add
total_spend, and support within_days on
received_email, opened_email and
clicked_email.
in_segment takes a segment key. A reference loop is
rejected on save.