Theme

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

MethodPathWhat it does
GET/api/v1/segmentsEvery segment with its live count
POST/api/v1/segmentsCreate one
GET/api/v1/segments/:keyOne segment, with rules and where it's used
PATCH/api/v1/segments/:keyUpdate it
DELETE/api/v1/segments/:keyDelete it
GET/api/v1/segments/:key/countJust the number
GET/api/v1/segments/:key/membersThe people, paginated
POST/api/v1/segments/previewCheck 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": [] }
}

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.