# Segments API

> Save filters over your contacts, list who matches, and follow tracked segments over time.

Base URL: `https://api.emailit.com/v2`. Authenticate with `Authorization: Bearer <API key>`.

## Create a segment — POST /segments

> Create a segment, a saved filter over your contacts drawn from all contacts or chosen audiences, and choose whether it's tracked. Alpha: open to the Emailit team only.

# Create a segment

Creates a segment: a saved filter over the workspace's contacts. Requires an API key with the `full` scope.

A segment holds the contacts from its source (the subscribers of `audience_ids`, or every contact when it's empty) that match its `conditions`. Membership is evaluated live each time the segment is counted, listed, previewed or used by a campaign that sends. See [Segments](/docs/segments/).

Each plan includes a number of segments per workspace, tracked or not. See [Limits](/docs/limits/#plan-limits).

`POST /segments`

> **Segments are in alpha:** Segments are open only to the Emailit team while we test them. Other requests, including every request made with an API key, return `403` with `error: "segments_alpha"`. See [Who can use segments](/docs/segments/#who-can-use-segments).

## Body parameters

- `name` (string, required): Name of the segment, up to 191 characters.

- `description` (string | null): Note for your team, up to 1,000 characters.

- `audience_ids` (string[]): The source: audience IDs (`aud_…`) in this workspace, up to 100. The segment only holds contacts subscribed to at least one of them. Empty or omitted means every contact in the workspace.

- `conditions` (object): The rules contacts must match, described under [Conditions](#conditions). Omit it to include everyone from the source.

- `tracked` (boolean): Store the segment's members so that contacts joining and leaving become events for [automations](/docs/automations/triggers/#segment-triggers) and [webhooks](/docs/webhooks/event-types/#segment-events). Included with Pro, Business and Custom. You choose it here and can't change it later. See [Tracked segments](/docs/segments/tracked/).

## Conditions

`conditions` holds groups of rules. The top-level `match` joins the groups, and each group's `match` joins its rules:

```json
{
  "match": "all",
  "groups": [
    { "match": "any", "rules": [{ "field": "email_domain", "operator": "in", "value": ["acme.com", "globex.io"] }] },
    { "match": "all", "rules": [{ "field": "status", "operator": "equals", "value": "subscribed" }] }
  ]
}
```

- `match` is `all` (default) or `any`, on the top level and in each group.
- Omit `conditions`, or send no groups, to include everyone from the source. Empty groups are dropped.
- The flat shape `{ "match": "any", "rules": [...] }` is also accepted and stored as one group.
- A segment can have up to 10 groups and 50 rules in total.

### Fields

| Field | Type | Notes |
| --- | --- | --- |
| `email` | string | |
| `email_domain` | string | The part of the address after `@`. |
| `first_name`, `last_name` | string | |
| `status` | enum | `subscribed` (not globally unsubscribed and subscribed to at least one audience, so campaigns can reach the contact) or `unsubscribed`. Operators: `equals`, `not_equals`. |
| `created_at`, `updated_at` | datetime | When the contact was created or last changed, compared in UTC. |
| `audience` | audience | Subscribed membership. `in` matches contacts subscribed to any of the audience IDs, `not_in` matches contacts subscribed to none of them. |
| `tags` | tags | The contact's [tags](/docs/contacts/tags-and-score/). Values are compared in lowercase. |
| `score` | score | The contact's [lead score](/docs/contacts/tags-and-score/#lead-score). |
| `custom_fields.<key>` | depends on the field | Text fields are `string`, number fields `number`, date fields `date` (`YYYY-MM-DD`), boolean fields `boolean`, select fields `enum` and multi-select fields `multi`. |
| `orders_count`, `total_spent`, `average_order_value` | metric | From the contact's [orders](/docs/commerce/). 0 for contacts without orders. Amounts are in the contact's order currency. |
| `first_order_at`, `last_order_at` | moment | Unset for contacts without orders. |
| `expected_next_order_at` | moment | The last order plus the contact's average gap between orders. Set from the second order on, and can be in the future. |
| `churn_risk` | enum | `low`, `medium` or `high`: time since the last order compared with the contact's usual gap (at least 14 days), or with 90 days for one-time buyers. Unset without orders. |
| `last_active_at` | moment | The last time the [tracking script](/docs/commerce/connect-your-shop/#the-tracking-script) saw the contact on your site. |
| `purchased` | purchase | Orders, see [Activity rules](#activity-rules). |
| `viewed_product` | view | Product views recorded by the tracking script. |
| `cart` | cart | Open and abandoned carts. |
| `used_coupon` | coupon | Orders that used a coupon code. |
| `campaign_activity` | campaign_activity | Campaign emails received, opened or clicked. |

[List segment fields](/docs/api-reference/segments/fields/) returns the fields of your workspace, including its custom fields and audiences, with the operators each one accepts.

### Operators

| Type | Operators |
| --- | --- |
| string | `equals`, `not_equals`, `contains`, `not_contains`, `starts_with`, `ends_with`, `in`, `not_in`, `is_set`, `is_not_set` |
| number | `equals`, `not_equals`, `greater_than`, `greater_than_or_equal`, `less_than`, `less_than_or_equal`, `between`, `is_set`, `is_not_set` |
| date | `on`, `before`, `after`, `between`, `in_last_days`, `more_than_days_ago`, `in_next_days`, `is_set`, `is_not_set` |
| datetime | `on`, `before`, `after`, `between`, `in_last_days`, `more_than_days_ago` |
| boolean | `is_true`, `is_false`, `is_set`, `is_not_set` |
| enum | `in`, `not_in`, `is_set`, `is_not_set` |
| multi | `in` (has any of), `contains_all` (has all of), `not_in` (has none of), `is_set`, `is_not_set` |
| audience | `in`, `not_in` |
| tags | `in` (has any of), `contains_all` (has all of), `not_in` (has none of), `is_set` (has any tag), `is_not_set` (has no tags) |
| score | `equals`, `not_equals`, `greater_than`, `greater_than_or_equal`, `less_than`, `less_than_or_equal`, `between` |
| metric | `equals`, `not_equals`, `greater_than`, `greater_than_or_equal`, `less_than`, `less_than_or_equal`, `between` |
| moment | `on`, `before`, `after`, `between`, `in_last_days`, `more_than_days_ago`, `in_next_days`, `is_set`, `is_not_set` |
| purchase, view, coupon | `has`, `has_not` |
| cart | `has_open_cart`, `has_abandoned_cart`, `has_no_open_cart` |
| campaign_activity | `received`, `not_received`, `opened`, `not_opened`, `clicked`, `not_clicked`, `received_not_opened`, `received_not_clicked` |

### Values

- Text comparisons on string fields ignore case. Select and multi-select values must match exactly.
- `not_equals`, `not_contains` and `not_in` also match contacts that have no value.
- `in`, `not_in` and `contains_all` take a list of up to 100 values. Text values can be up to 500 characters.
- `between` takes `[from, to]`, both included: two numbers or two `YYYY-MM-DD` dates.
- `on`, `before` and `after` take a `YYYY-MM-DD` date. `before` and `after` don't include that day.
- `in_last_days`, `more_than_days_ago` and `in_next_days` take a whole number of days from 1 to 3650, counted from the moment the segment is evaluated. Date custom fields compare calendar days in UTC; `created_at` and `updated_at` use exact times, so `in_last_days` with `7` means the last 7 × 24 hours.
- `is_set`, `is_not_set`, `is_true` and `is_false` take no value. `is_true` matches `true`, `1`, `yes` and `on`; `is_false` matches `false`, `0`, `no` and `off`.
- A saved rule that no longer applies, for example after its custom field changed type, matches no contacts. Rules on a deleted custom field keep working from the values contacts still have, but new rules must use an existing field.

### Activity rules

`purchased`, `viewed_product`, `cart`, `used_coupon` and `campaign_activity` take an object as `value`. Every key is optional.

| Field | Value keys |
| --- | --- |
| `purchased` | `days`: only orders placed in the last N days. `product_ids`: orders with any of these products (your shop's product IDs). `categories`: orders with a product in any of these categories. `min_count`: at least this many matching orders (default 1, up to 1000). Canceled orders don't count. |
| `viewed_product` | `days`, `product_ids`, `categories` and `min_count` as above, counting product views. |
| `cart` | `days` with `has_abandoned_cart` only: carts abandoned in the last N days. `has_open_cart` matches an active cart, `has_no_open_cart` matches contacts with no active or abandoned cart. |
| `used_coupon` | `days`, and `coupon`: the key of one [coupon](/docs/commerce/coupons/). Without `coupon`, any code counts. |
| `campaign_activity` | `campaign_id`: one campaign (`cmp_...`), any campaign when absent. `days`: only the last N days, all time when absent. |

`days` is a whole number from 1 to 3650. `has_not` is the opposite of `has` with the same value.

```json
{
  "match": "all",
  "groups": [
    { "match": "all", "rules": [
      { "field": "purchased", "operator": "has", "value": { "categories": ["Shoes"], "days": 180 } },
      { "field": "churn_risk", "operator": "in", "value": ["medium", "high"] },
      { "field": "campaign_activity", "operator": "clicked", "value": { "days": 90 } }
    ] }
  ]
}
```

`received_not_opened` and `received_not_clicked` match contacts who got at least one matching campaign email and opened or clicked none of them. Opens are approximate: Apple Mail loads images for every email it receives.

## Returns

Returns `201 Created` with the [segment object](/docs/api-reference/segments/get/), including `contacts_count` and `subscribed_count`. A new tracked segment starts with `tracking.status` set to `syncing` while Emailit records its current members.

| Status | When |
| --- | --- |
| `400` | `name` is missing, or a field has the wrong type. |
| `403` | `tracked` is `true` and the plan doesn't include tracked segments. The body is `{"error": "plan_required", "required_plan": "pro", ...}`. |
| `422` | A field or rule is invalid: `errors` is keyed by its path, such as `conditions.groups.0.rules.1.value`, and `message` repeats the first problem. Also returned when the workspace has reached its plan's segment limit; that body includes `usage.used` and `usage.limit`. |

**Request** `POST /segments`

**cURL**

```bash
curl -X POST https://api.emailit.com/v2/segments \
  -H "Authorization: Bearer $EMAILIT_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Pro customers renewing soon",
    "audience_ids": ["aud_2nYs8Qm4Hc1Zx7Vb3Ne6Tg9Lk2a"],
    "conditions": {
      "match": "all",
      "groups": [{
        "match": "all",
        "rules": [
          { "field": "custom_fields.plan", "operator": "in", "value": ["pro", "enterprise"] },
          { "field": "custom_fields.renews_on", "operator": "in_next_days", "value": 30 }
        ]
      }]
    },
    "tracked": true
  }'
```

**Node.js**

```javascript
const res = await fetch('https://api.emailit.com/v2/segments', {
  method: 'POST',
  headers: {
    Authorization: `Bearer ${process.env.EMAILIT_API_KEY}`,
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
    name: 'Pro customers renewing soon',
    audience_ids: ['aud_2nYs8Qm4Hc1Zx7Vb3Ne6Tg9Lk2a'],
    conditions: {
      match: 'all',
      groups: [{
        match: 'all',
        rules: [
          { field: 'custom_fields.plan', operator: 'in', value: ['pro', 'enterprise'] },
          { field: 'custom_fields.renews_on', operator: 'in_next_days', value: 30 },
        ],
      }],
    },
    tracked: true,
  }),
});
const segment = await res.json();
```

**Python**

```python
import os, requests

r = requests.post(
    "https://api.emailit.com/v2/segments",
    headers={"Authorization": f"Bearer {os.environ['EMAILIT_API_KEY']}"},
    json={
        "name": "Pro customers renewing soon",
        "audience_ids": ["aud_2nYs8Qm4Hc1Zx7Vb3Ne6Tg9Lk2a"],
        "conditions": {
            "match": "all",
            "groups": [{
                "match": "all",
                "rules": [
                    {"field": "custom_fields.plan", "operator": "in", "value": ["pro", "enterprise"]},
                    {"field": "custom_fields.renews_on", "operator": "in_next_days", "value": 30},
                ],
            }],
        },
        "tracked": True,
    },
)
segment = r.json()
```

**PHP**

```php
$client = new GuzzleHttp\Client(['base_uri' => 'https://api.emailit.com/v2/']);

$response = $client->post('segments', [
    'headers' => ['Authorization' => 'Bearer ' . getenv('EMAILIT_API_KEY')],
    'json' => [
        'name' => 'Pro customers renewing soon',
        'audience_ids' => ['aud_2nYs8Qm4Hc1Zx7Vb3Ne6Tg9Lk2a'],
        'conditions' => [
            'match' => 'all',
            'groups' => [[
                'match' => 'all',
                'rules' => [
                    ['field' => 'custom_fields.plan', 'operator' => 'in', 'value' => ['pro', 'enterprise']],
                    ['field' => 'custom_fields.renews_on', 'operator' => 'in_next_days', 'value' => 30],
                ],
            ]],
        ],
        'tracked' => true,
    ],
]);
$segment = json_decode($response->getBody(), true);
```

**201**

```json
{
  "object": "segment",
  "id": "seg_2nYs9Kd1Lq3vB8wXcE4fT7uRm0p",
  "name": "Pro customers renewing soon",
  "description": null,
  "audience_ids": ["aud_2nYs8Qm4Hc1Zx7Vb3Ne6Tg9Lk2a"],
  "conditions": {
    "match": "all",
    "groups": [
      {
        "match": "all",
        "rules": [
          { "field": "custom_fields.plan", "operator": "in", "value": ["pro", "enterprise"] },
          { "field": "custom_fields.renews_on", "operator": "in_next_days", "value": 30 }
        ]
      }
    ]
  },
  "tracked": true,
  "tracking": {
    "status": "syncing",
    "synced_at": null
  },
  "contacts_count": 412,
  "subscribed_count": 398,
  "created_at": "2026-10-18T12:00:00.000000+00:00",
  "updated_at": "2026-10-18T12:00:00.000000+00:00"
}
```

**403**

```json
{
  "error": "plan_required",
  "message": "Tracked segments are included with Pro and Business.",
  "required_plan": "pro"
}
```

**422 Validation**

```json
{
  "message": "Validation failed. conditions.groups.0.rules.1.value: Enter a whole number of days between 1 and 3650.",
  "errors": {
    "conditions.groups.0.rules.1.value": [
      "Enter a whole number of days between 1 and 3650."
    ]
  }
}
```

**422 Limit**

```json
{
  "error": "Pay as you go includes 3 segments.",
  "message": "Pay as you go includes 3 segments.",
  "usage": {
    "used": 3,
    "limit": 3
  }
}
```

---
Source: https://emailit.com/docs/api-reference/segments/create/

## Retrieve a segment — GET /segments/{id}

> Retrieve a segment with its source, rules, tracking state and live contact counts. Alpha: open to the Emailit team only.

# Retrieve a segment

Retrieves a segment and counts its contacts at the moment you call it. Requires an API key with the `full` scope.

`GET /segments/{id}`

> **Segments are in alpha:** Segments are open only to the Emailit team while we test them. Other requests, including every request made with an API key, return `403` with `error: "segments_alpha"`. See [Who can use segments](/docs/segments/#who-can-use-segments).

## Path parameters

- `id` (string, required): The segment ID (`seg_…`).

## Returns

Returns the segment object.

- `object` (string): Always `segment`.

- `id` (string): Segment ID, prefixed `seg_`.

- `name` (string): Name of the segment.

- `description` (string | null): Note for your team.

- `audience_ids` (string[]): The source audiences. Empty means every contact in the workspace.

- `conditions` (object): The rules, as `{ "match", "groups": [{ "match", "rules": [...] }] }`. See [Create a segment](/docs/api-reference/segments/create/#conditions).

- `tracked` (boolean): Whether the segment stores its members and reports joins and leaves. See [Tracked segments](/docs/segments/tracked/).

- `tracking` (object | null): `null` for segments that aren't tracked. For tracked segments: - `status`: `active` when members are kept up to date, `syncing` while Emailit records the current members after the segment was created or tracking resumed, or `paused` when the workspace's plan no longer includes tracked segments. - `synced_at`: when the whole segment was last compared with its rules, or `null` before the first comparison.

- `contacts_count` (integer): Contacts that match right now.

- `subscribed_count` (integer): The part of `contacts_count` that campaigns can send to: contacts that aren't globally unsubscribed and are subscribed to at least one audience. Suppressed addresses are still counted.

- `created_at, updated_at` (string): Timestamps in UTC.

Returns `404` if the segment doesn't exist.

**Request** `GET /segments/{id}`

**cURL**

```bash
curl https://api.emailit.com/v2/segments/seg_2nYs9Kd1Lq3vB8wXcE4fT7uRm0p \
  -H "Authorization: Bearer $EMAILIT_API_KEY"
```

**Node.js**

```javascript
const res = await fetch('https://api.emailit.com/v2/segments/seg_2nYs9Kd1Lq3vB8wXcE4fT7uRm0p', {
  headers: { Authorization: `Bearer ${process.env.EMAILIT_API_KEY}` },
});
const segment = await res.json();
```

**Python**

```python
import os, requests

r = requests.get(
    "https://api.emailit.com/v2/segments/seg_2nYs9Kd1Lq3vB8wXcE4fT7uRm0p",
    headers={"Authorization": f"Bearer {os.environ['EMAILIT_API_KEY']}"},
)
segment = r.json()
```

**PHP**

```php
$client = new GuzzleHttp\Client(['base_uri' => 'https://api.emailit.com/v2/']);

$response = $client->get('segments/seg_2nYs9Kd1Lq3vB8wXcE4fT7uRm0p', [
    'headers' => ['Authorization' => 'Bearer ' . getenv('EMAILIT_API_KEY')],
]);
$segment = json_decode($response->getBody(), true);
```

**200**

```json
{
  "object": "segment",
  "id": "seg_2nYs9Kd1Lq3vB8wXcE4fT7uRm0p",
  "name": "Pro customers renewing soon",
  "description": "Pro and Enterprise plans that renew in the next 30 days.",
  "audience_ids": ["aud_2nYs8Qm4Hc1Zx7Vb3Ne6Tg9Lk2a"],
  "conditions": {
    "match": "all",
    "groups": [
      {
        "match": "all",
        "rules": [
          { "field": "custom_fields.plan", "operator": "in", "value": ["pro", "enterprise"] },
          { "field": "custom_fields.renews_on", "operator": "in_next_days", "value": 30 }
        ]
      }
    ]
  },
  "tracked": true,
  "tracking": {
    "status": "active",
    "synced_at": "2026-10-18T00:30:04.211000+00:00"
  },
  "contacts_count": 412,
  "subscribed_count": 398,
  "created_at": "2026-10-02T09:14:03.551000+00:00",
  "updated_at": "2026-10-02T09:14:03.551000+00:00"
}
```

**404**

```json
{
  "error": "Segment not found"
}
```

---
Source: https://emailit.com/docs/api-reference/segments/get/

## Update a segment — POST /segments/{id}

> Change a segment's name, description, source audiences or rules. Whether a segment is tracked can't be changed. Alpha: open to the Emailit team only.

# Update a segment

Updates the fields you pass and leaves the others unchanged. `audience_ids` and `conditions` are replaced as a whole. Requires an API key with the `full` scope.

Campaigns evaluate a segment when they send, so new rules apply to every campaign that hasn't sent yet, including scheduled ones.

On a [tracked segment](/docs/segments/tracked/), changing `audience_ids` or `conditions` compares the stored members with the new rules. Contacts who join or leave because of the change send `segment.contact_added` and `segment.contact_removed` events with `reason` set to `segment_updated`. Webhooks receive them, but they don't start automations.

`POST /segments/{id}`

> **Segments are in alpha:** Segments are open only to the Emailit team while we test them. Other requests, including every request made with an API key, return `403` with `error: "segments_alpha"`. See [Who can use segments](/docs/segments/#who-can-use-segments).

## Path parameters

- `id` (string, required): The segment ID (`seg_…`).

## Body parameters

- `name` (string): New name, up to 191 characters. Can't be empty.

- `description` (string | null): Note for your team, up to 1,000 characters. `null` or an empty string clears it.

- `audience_ids` (string[]): Source audience IDs. `[]` means every contact in the workspace.

- `conditions` (object): The rules. See [Create a segment](/docs/api-reference/segments/create/#conditions).

- `tracked` (boolean): Accepted only with the segment's current value. Tracking is chosen when a segment is created; to change it, create a new segment.

## Returns

Returns the updated [segment object](/docs/api-reference/segments/get/) with fresh counts.

| Status | When |
| --- | --- |
| `404` | The segment doesn't exist. |
| `422` | A field or rule is invalid, or `tracked` differs from the segment's current value. `errors` is keyed by field path. |

**Request** `POST /segments/{id}`

**cURL**

```bash
curl -X POST https://api.emailit.com/v2/segments/seg_2nYs9Kd1Lq3vB8wXcE4fT7uRm0p \
  -H "Authorization: Bearer $EMAILIT_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "name": "Pro customers renewing this month" }'
```

**Node.js**

```javascript
const res = await fetch('https://api.emailit.com/v2/segments/seg_2nYs9Kd1Lq3vB8wXcE4fT7uRm0p', {
  method: 'POST',
  headers: {
    Authorization: `Bearer ${process.env.EMAILIT_API_KEY}`,
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({ name: 'Pro customers renewing this month' }),
});
const segment = await res.json();
```

**Python**

```python
import os, requests

r = requests.post(
    "https://api.emailit.com/v2/segments/seg_2nYs9Kd1Lq3vB8wXcE4fT7uRm0p",
    headers={"Authorization": f"Bearer {os.environ['EMAILIT_API_KEY']}"},
    json={"name": "Pro customers renewing this month"},
)
segment = r.json()
```

**PHP**

```php
$client = new GuzzleHttp\Client(['base_uri' => 'https://api.emailit.com/v2/']);

$response = $client->post('segments/seg_2nYs9Kd1Lq3vB8wXcE4fT7uRm0p', [
    'headers' => ['Authorization' => 'Bearer ' . getenv('EMAILIT_API_KEY')],
    'json' => ['name' => 'Pro customers renewing this month'],
]);
$segment = json_decode($response->getBody(), true);
```

**200**

```json
{
  "object": "segment",
  "id": "seg_2nYs9Kd1Lq3vB8wXcE4fT7uRm0p",
  "name": "Pro customers renewing this month",
  "description": "Pro and Enterprise plans that renew in the next 30 days.",
  "audience_ids": ["aud_2nYs8Qm4Hc1Zx7Vb3Ne6Tg9Lk2a"],
  "conditions": {
    "match": "all",
    "groups": [
      {
        "match": "all",
        "rules": [
          { "field": "custom_fields.plan", "operator": "in", "value": ["pro", "enterprise"] },
          { "field": "custom_fields.renews_on", "operator": "in_next_days", "value": 30 }
        ]
      }
    ]
  },
  "tracked": true,
  "tracking": {
    "status": "active",
    "synced_at": "2026-10-18T00:30:04.211000+00:00"
  },
  "contacts_count": 412,
  "subscribed_count": 398,
  "created_at": "2026-10-02T09:14:03.551000+00:00",
  "updated_at": "2026-10-18T12:00:00.000000+00:00"
}
```

**404**

```json
{
  "error": "Segment not found"
}
```

**422**

```json
{
  "message": "Validation failed. tracked: Tracking is chosen when a segment is created and can't be changed. Create a new segment instead.",
  "errors": {
    "tracked": [
      "Tracking is chosen when a segment is created and can't be changed. Create a new segment instead."
    ]
  }
}
```

---
Source: https://emailit.com/docs/api-reference/segments/update/

## List segments — GET /segments

> List the segments in a workspace, newest first, with optional live counts and the plan's segment usage. Alpha: open to the Emailit team only.

# List segments

Returns the workspace's segments, newest first, with how many of the plan's segments are in use. Requires an API key with the `full` scope.

`GET /segments`

> **Segments are in alpha:** Segments are open only to the Emailit team while we test them. Other requests, including every request made with an API key, return `403` with `error: "segments_alpha"`. See [Who can use segments](/docs/segments/#who-can-use-segments).

## Query parameters

- `page` (integer): Page number, starting at 1.

- `limit` (integer): Segments per page, from 1 to 100.

- `search` (string): Case-insensitive match on part of the segment name.

- `with_counts` (boolean): Add `contacts_count` and `subscribed_count` to each segment. Counting evaluates every segment on the page, so it's off by default.

- `match`, `order`, `direction`: see [Filtering](https://emailit.com/docs/api-reference/filtering/).

### Filter keys

Filters use `key.condition=value` query parameters, for example `name.contains=customers` or `created_at.after=2026-09-01`. See [Filtering](/docs/api-reference/filtering/) for the conditions per type.

| Key | Type | Notes |
| --- | --- | --- |
| `name` | string | |
| `created_at` | date | |
| `updated_at` | date | |

Sort keys for `order`: `name`, `created_at`, `updated_at`.

## Returns

- `data` (object[]): [Segment objects](/docs/api-reference/segments/get/) on this page. `contacts_count` and `subscribed_count` are only included with `with_counts`.

- `total_records` (integer): Number of segments that match the query.

- `usage` (object): The workspace's segments against its plan: `used` (all segments, tracked or not), `limit` (segments the plan includes) and `tracking_allowed` (whether the plan includes tracked segments). See [Limits](/docs/limits/#plan-limits).

- `next_page_url` (string | null): Path of the next page, or `null` on the last page. It carries only `page` and `limit`; add your search and filters again when you follow it.

- `previous_page_url` (string | null): Path of the previous page, or `null` on the first page.

**Request** `GET /segments`

**cURL**

```bash
curl -G https://api.emailit.com/v2/segments \
  -H "Authorization: Bearer $EMAILIT_API_KEY" \
  -d with_counts=true
```

**Node.js**

```javascript
const params = new URLSearchParams({ with_counts: 'true' });
const res = await fetch(`https://api.emailit.com/v2/segments?${params}`, {
  headers: { Authorization: `Bearer ${process.env.EMAILIT_API_KEY}` },
});
const { data: segments, usage } = await res.json();
```

**Python**

```python
import os, requests

r = requests.get(
    "https://api.emailit.com/v2/segments",
    headers={"Authorization": f"Bearer {os.environ['EMAILIT_API_KEY']}"},
    params={"with_counts": "true"},
)
segments = r.json()["data"]
```

**PHP**

```php
$client = new GuzzleHttp\Client(['base_uri' => 'https://api.emailit.com/v2/']);

$response = $client->get('segments', [
    'headers' => ['Authorization' => 'Bearer ' . getenv('EMAILIT_API_KEY')],
    'query' => ['with_counts' => 'true'],
]);
$segments = json_decode($response->getBody(), true)['data'];
```

**200**

```json
{
  "data": [
    {
      "object": "segment",
      "id": "seg_2nYs9Kd1Lq3vB8wXcE4fT7uRm0p",
      "name": "Pro customers renewing soon",
      "description": "Pro and Enterprise plans that renew in the next 30 days.",
      "audience_ids": ["aud_2nYs8Qm4Hc1Zx7Vb3Ne6Tg9Lk2a"],
      "conditions": {
        "match": "all",
        "groups": [
          {
            "match": "all",
            "rules": [
              { "field": "custom_fields.plan", "operator": "in", "value": ["pro", "enterprise"] },
              { "field": "custom_fields.renews_on", "operator": "in_next_days", "value": 30 }
            ]
          }
        ]
      },
      "tracked": true,
      "tracking": {
        "status": "active",
        "synced_at": "2026-10-18T00:30:04.211000+00:00"
      },
      "contacts_count": 412,
      "subscribed_count": 398,
      "created_at": "2026-10-02T09:14:03.551000+00:00",
      "updated_at": "2026-10-02T09:14:03.551000+00:00"
    }
  ],
  "total_records": 1,
  "usage": {
    "used": 1,
    "limit": 10,
    "tracking_allowed": true
  },
  "next_page_url": null,
  "previous_page_url": null
}
```

---
Source: https://emailit.com/docs/api-reference/segments/list/

## Delete a segment — DELETE /segments/{id}

> Delete a segment. Draft campaigns that send to it lose it; drafts that exclude it can't send until you replace the exclusion. Scheduled or sending campaigns and automations that use the segment block the deletion. Alpha: open to the Emailit team only.

# Delete a segment

Deletes a segment. Requires an API key with the `full` scope.

- A segment that a campaign uses while it's scheduled, queued, sending or testing can't be deleted. Change the campaign's recipients first.
- A segment can't be deleted while any automation that isn't deleted, in any status, uses it: in an **Added to segment** or **Removed from segment** trigger, in a goal, **Wait until** step or exit condition on those events, or in a **Segment** rule of a condition. Change those automations first.
- Draft campaigns that send to the segment lose it from their recipients, and `removed_from_campaigns` says how many. Drafts that exclude the segment keep the exclusion, so they can't be sent until you replace it: dropping it would send to the people you meant to leave out. Sent, canceled and archived campaigns keep the reference as history.
- For a tracked segment, its stored members and growth history are deleted too.

`DELETE /segments/{id}`

> **Segments are in alpha:** Segments are open only to the Emailit team while we test them. Other requests, including every request made with an API key, return `403` with `error: "segments_alpha"`. See [Who can use segments](/docs/segments/#who-can-use-segments).

## Path parameters

- `id` (string, required): The segment ID (`seg_…`).

## Returns

- `object` (string): Always `segment`.

- `id` (string): ID of the deleted segment.

- `name` (string): Its name.

- `deleted` (boolean): Always `true`.

- `removed_from_campaigns` (integer): Number of draft campaigns that no longer send to the segment.

| Status | When |
| --- | --- |
| `404` | The segment doesn't exist. |
| `409` | A scheduled, queued, sending or testing campaign uses the segment, or an automation starts from it. The message names them. |

**Request** `DELETE /segments/{id}`

**cURL**

```bash
curl -X DELETE https://api.emailit.com/v2/segments/seg_2nYs9Kd1Lq3vB8wXcE4fT7uRm0p \
  -H "Authorization: Bearer $EMAILIT_API_KEY"
```

**Node.js**

```javascript
const res = await fetch('https://api.emailit.com/v2/segments/seg_2nYs9Kd1Lq3vB8wXcE4fT7uRm0p', {
  method: 'DELETE',
  headers: { Authorization: `Bearer ${process.env.EMAILIT_API_KEY}` },
});
const result = await res.json();
```

**Python**

```python
import os, requests

r = requests.delete(
    "https://api.emailit.com/v2/segments/seg_2nYs9Kd1Lq3vB8wXcE4fT7uRm0p",
    headers={"Authorization": f"Bearer {os.environ['EMAILIT_API_KEY']}"},
)
result = r.json()
```

**PHP**

```php
$client = new GuzzleHttp\Client(['base_uri' => 'https://api.emailit.com/v2/']);

$response = $client->delete('segments/seg_2nYs9Kd1Lq3vB8wXcE4fT7uRm0p', [
    'headers' => ['Authorization' => 'Bearer ' . getenv('EMAILIT_API_KEY')],
]);
$result = json_decode($response->getBody(), true);
```

**200**

```json
{
  "object": "segment",
  "id": "seg_2nYs9Kd1Lq3vB8wXcE4fT7uRm0p",
  "name": "Pro customers renewing soon",
  "deleted": true,
  "removed_from_campaigns": 1
}
```

**409 Campaigns**

```json
{
  "error": "This segment is used by campaigns that are scheduled or sending: October launch. Change their recipients first.",
  "message": "This segment is used by campaigns that are scheduled or sending: October launch. Change their recipients first."
}
```

**409 Automations**

```json
{
  "error": "This segment is used by automations: Renewal reminder. Change their triggers, conditions or exit conditions first.",
  "message": "This segment is used by automations: Renewal reminder. Change their triggers, conditions or exit conditions first."
}
```

**404**

```json
{
  "error": "Segment not found"
}
```

---
Source: https://emailit.com/docs/api-reference/segments/delete/

## List segment contacts — GET /segments/{id}/contacts

> List the contacts that match a segment right now, with search, the contacts list filters and, for tracked segments, when each contact joined. Alpha: open to the Emailit team only.

# List segment contacts

Returns the contacts that match the segment at the moment you call it, newest first. Requires an API key with the `full` scope.

`GET /segments/{id}/contacts`

> **Segments are in alpha:** Segments are open only to the Emailit team while we test them. Other requests, including every request made with an API key, return `403` with `error: "segments_alpha"`. See [Who can use segments](/docs/segments/#who-can-use-segments).

## Path parameters

- `id` (string, required): The segment ID (`seg_…`).

## Query parameters

- `page` (integer): Page number, starting at 1.

- `limit` (integer): Contacts per page, from 1 to 100.

- `search` (string): Case-insensitive match on part of the email address, first name or last name.

- `match`, `order`, `direction`: see [Filtering](https://emailit.com/docs/api-reference/filtering/).

### Filter keys

The contacts of a segment accept the same filter and sort keys as [List contacts](/docs/api-reference/contacts/list/), applied on top of the segment, for example `email.ends_with=acme.com`.

Filter and sort keys: see [Filtering](https://emailit.com/docs/api-reference/filtering/).

## Returns

- `data` (object[]): Contacts on this page, each with `object`, `id`, `email`, `first_name`, `last_name`, `custom_fields`, `unsubscribed`, `audiences` (`id`, `name`, `subscribed`), `created_at` and `updated_at`. Contacts of a [tracked segment](/docs/segments/tracked/) also have `joined_at`.

- `data[].joined_at` (string | null): Tracked segments only: when the contact's current stay in the segment began. `null` until tracking has recorded the contact, for example right after it started matching, while the segment is `syncing`, or while tracking is `paused`.

- `total_records` (integer): Number of contacts that match the segment, the search and the filters.

- `subscribed_count` (integer): How many of them campaigns can send to: not globally unsubscribed and subscribed to at least one audience.

- `next_page_url` (string | null): Path of the next page, or `null` on the last page. It carries `page`, `limit` and `search`; add your filters again when you follow it.

- `previous_page_url` (string | null): Path of the previous page, or `null` on the first page.

Returns `404` if the segment doesn't exist.

**Request** `GET /segments/{id}/contacts`

**cURL**

```bash
curl -G https://api.emailit.com/v2/segments/seg_2nYs9Kd1Lq3vB8wXcE4fT7uRm0p/contacts \
  -H "Authorization: Bearer $EMAILIT_API_KEY" \
  -d email.ends_with=acme.com
```

**Node.js**

```javascript
const params = new URLSearchParams({ 'email.ends_with': 'acme.com' });
const res = await fetch(
  `https://api.emailit.com/v2/segments/seg_2nYs9Kd1Lq3vB8wXcE4fT7uRm0p/contacts?${params}`,
  { headers: { Authorization: `Bearer ${process.env.EMAILIT_API_KEY}` } },
);
const { data: contacts } = await res.json();
```

**Python**

```python
import os, requests

r = requests.get(
    "https://api.emailit.com/v2/segments/seg_2nYs9Kd1Lq3vB8wXcE4fT7uRm0p/contacts",
    headers={"Authorization": f"Bearer {os.environ['EMAILIT_API_KEY']}"},
    params={"email.ends_with": "acme.com"},
)
contacts = r.json()["data"]
```

**PHP**

```php
$client = new GuzzleHttp\Client(['base_uri' => 'https://api.emailit.com/v2/']);

$response = $client->get('segments/seg_2nYs9Kd1Lq3vB8wXcE4fT7uRm0p/contacts', [
    'headers' => ['Authorization' => 'Bearer ' . getenv('EMAILIT_API_KEY')],
    'query' => ['email.ends_with' => 'acme.com'],
]);
$contacts = json_decode($response->getBody(), true)['data'];
```

**200**

```json
{
  "data": [
    {
      "object": "contact",
      "id": "con_2nYs7Ab3Kd9Lm1Qw5Er8Ty2Ui4o",
      "email": "ada@acme.com",
      "first_name": "Ada",
      "last_name": "Lovelace",
      "custom_fields": {
        "plan": "pro",
        "renews_on": "2026-10-20"
      },
      "unsubscribed": false,
      "audiences": [
        {
          "id": "aud_2nYs8Qm4Hc1Zx7Vb3Ne6Tg9Lk2a",
          "name": "Customers",
          "subscribed": true
        }
      ],
      "created_at": "2026-03-11T08:00:00.000000+00:00",
      "updated_at": "2026-09-30T16:42:10.000000+00:00",
      "joined_at": "2026-10-03T00:30:02.874000+00:00"
    }
  ],
  "total_records": 1,
  "subscribed_count": 1,
  "next_page_url": null,
  "previous_page_url": null
}
```

**404**

```json
{
  "error": "Segment not found"
}
```

---
Source: https://emailit.com/docs/api-reference/segments/contacts/

## Retrieve segment growth — GET /segments/{id}/growth

> Daily member counts, joins and leaves of a tracked segment, one row per UTC day for up to 365 days. Alpha: open to the Emailit team only.

# Retrieve segment growth

Returns the history of a [tracked segment](/docs/segments/tracked/): one row per UTC day, oldest first, ending today. It's the data behind the **Growth** chart on the segment page. Requires an API key with the `full` scope.

History starts when tracking starts. Contacts recorded by the first count after the segment was created, or after tracking resumed, count as members but not as joins.

`GET /segments/{id}/growth`

> **Segments are in alpha:** Segments are open only to the Emailit team while we test them. Other requests, including every request made with an API key, return `403` with `error: "segments_alpha"`. See [Who can use segments](/docs/segments/#who-can-use-segments).

## Path parameters

- `id` (string, required): The segment ID (`seg_…`).

## Query parameters

- `days` (integer): Number of days to return, from 1 to 365, ending today.

## Returns

- `object` (string): Always `segment_growth`.

- `segment_id` (string): The segment ID.

- `data` (object[]): One row per day.

- `data[].date` (string): The UTC day, `YYYY-MM-DD`.

- `data[].members_count` (integer | null): Members at the end of the day, or the latest count for today. Days without a new count carry the previous value forward, for example while tracking is paused. `null` before tracking started.

- `data[].joined_count` (integer): Contacts that joined the segment that day.

- `data[].left_count` (integer): Contacts that left the segment that day.

| Status | When |
| --- | --- |
| `404` | The segment doesn't exist. |
| `422` | The segment isn't tracked. |

**Request** `GET /segments/{id}/growth`

**cURL**

```bash
curl -G https://api.emailit.com/v2/segments/seg_2nYs9Kd1Lq3vB8wXcE4fT7uRm0p/growth \
  -H "Authorization: Bearer $EMAILIT_API_KEY" \
  -d days=7
```

**Node.js**

```javascript
const res = await fetch(
  'https://api.emailit.com/v2/segments/seg_2nYs9Kd1Lq3vB8wXcE4fT7uRm0p/growth?days=7',
  { headers: { Authorization: `Bearer ${process.env.EMAILIT_API_KEY}` } },
);
const { data: days } = await res.json();
```

**Python**

```python
import os, requests

r = requests.get(
    "https://api.emailit.com/v2/segments/seg_2nYs9Kd1Lq3vB8wXcE4fT7uRm0p/growth",
    headers={"Authorization": f"Bearer {os.environ['EMAILIT_API_KEY']}"},
    params={"days": 7},
)
days = r.json()["data"]
```

**PHP**

```php
$client = new GuzzleHttp\Client(['base_uri' => 'https://api.emailit.com/v2/']);

$response = $client->get('segments/seg_2nYs9Kd1Lq3vB8wXcE4fT7uRm0p/growth', [
    'headers' => ['Authorization' => 'Bearer ' . getenv('EMAILIT_API_KEY')],
    'query' => ['days' => 7],
]);
$days = json_decode($response->getBody(), true)['data'];
```

**200**

```json
{
  "object": "segment_growth",
  "segment_id": "seg_2nYs9Kd1Lq3vB8wXcE4fT7uRm0p",
  "data": [
    { "date": "2026-10-12", "members_count": null, "joined_count": 0, "left_count": 0 },
    { "date": "2026-10-13", "members_count": 380, "joined_count": 0, "left_count": 0 },
    { "date": "2026-10-14", "members_count": 391, "joined_count": 14, "left_count": 3 },
    { "date": "2026-10-15", "members_count": 391, "joined_count": 0, "left_count": 0 },
    { "date": "2026-10-16", "members_count": 402, "joined_count": 12, "left_count": 1 },
    { "date": "2026-10-17", "members_count": 405, "joined_count": 6, "left_count": 3 },
    { "date": "2026-10-18", "members_count": 412, "joined_count": 9, "left_count": 2 }
  ]
}
```

**422**

```json
{
  "error": "Growth is recorded for tracked segments only.",
  "message": "Growth is recorded for tracked segments only."
}
```

**404**

```json
{
  "error": "Segment not found"
}
```

---
Source: https://emailit.com/docs/api-reference/segments/growth/

## Preview a segment — POST /segments/preview

> Count and sample the contacts a segment definition would hold, without saving it. Alpha: open to the Emailit team only.

# Preview a segment

Checks a segment definition without saving it: returns how many contacts match and a sample of them. The definition is validated like [Create a segment](/docs/api-reference/segments/create/), and a preview doesn't count toward the plan's segment limit. Requires an API key with the `full` scope.

`POST /segments/preview`

> **Segments are in alpha:** Segments are open only to the Emailit team while we test them. Other requests, including every request made with an API key, return `403` with `error: "segments_alpha"`. See [Who can use segments](/docs/segments/#who-can-use-segments).

## Body parameters

- `audience_ids` (string[]): Audience IDs the segment would draw from. Empty or omitted means every contact.

- `conditions` (object): The rules. See [Create a segment](/docs/api-reference/segments/create/#conditions).

- `limit` (integer): Number of sample contacts, from 1 to 25.

## Returns

- `object` (string): Always `segment_preview`.

- `audience_ids` (string[]): The source audiences, without duplicates.

- `conditions` (object): The rules as they would be saved: a flat `{ match, rules }` becomes one group and empty groups are dropped.

- `contacts_count` (integer): Contacts that match.

- `subscribed_count` (integer): How many of them campaigns can send to.

- `contacts` (object[]): The newest matching contacts, in the same shape as [List segment contacts](/docs/api-reference/segments/contacts/).

Returns `422` with `errors` keyed by field path if the definition is invalid.

**Request** `POST /segments/preview`

**cURL**

```bash
curl -X POST https://api.emailit.com/v2/segments/preview \
  -H "Authorization: Bearer $EMAILIT_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "conditions": { "rules": [{ "field": "email_domain", "operator": "equals", "value": "acme.com" }] },
    "limit": 5
  }'
```

**Node.js**

```javascript
const res = await fetch('https://api.emailit.com/v2/segments/preview', {
  method: 'POST',
  headers: {
    Authorization: `Bearer ${process.env.EMAILIT_API_KEY}`,
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
    conditions: { rules: [{ field: 'email_domain', operator: 'equals', value: 'acme.com' }] },
    limit: 5,
  }),
});
const preview = await res.json();
```

**Python**

```python
import os, requests

r = requests.post(
    "https://api.emailit.com/v2/segments/preview",
    headers={"Authorization": f"Bearer {os.environ['EMAILIT_API_KEY']}"},
    json={
        "conditions": {"rules": [{"field": "email_domain", "operator": "equals", "value": "acme.com"}]},
        "limit": 5,
    },
)
preview = r.json()
```

**PHP**

```php
$client = new GuzzleHttp\Client(['base_uri' => 'https://api.emailit.com/v2/']);

$response = $client->post('segments/preview', [
    'headers' => ['Authorization' => 'Bearer ' . getenv('EMAILIT_API_KEY')],
    'json' => [
        'conditions' => ['rules' => [['field' => 'email_domain', 'operator' => 'equals', 'value' => 'acme.com']]],
        'limit' => 5,
    ],
]);
$preview = json_decode($response->getBody(), true);
```

**200**

```json
{
  "object": "segment_preview",
  "audience_ids": [],
  "conditions": {
    "match": "all",
    "groups": [
      {
        "match": "all",
        "rules": [
          { "field": "email_domain", "operator": "equals", "value": "acme.com" }
        ]
      }
    ]
  },
  "contacts_count": 8,
  "subscribed_count": 8,
  "contacts": [
    {
      "object": "contact",
      "id": "con_2nYs7Ab3Kd9Lm1Qw5Er8Ty2Ui4o",
      "email": "ada@acme.com",
      "first_name": "Ada",
      "last_name": "Lovelace",
      "custom_fields": {
        "plan": "pro",
        "renews_on": "2026-10-20"
      },
      "unsubscribed": false,
      "audiences": [
        {
          "id": "aud_2nYs8Qm4Hc1Zx7Vb3Ne6Tg9Lk2a",
          "name": "Customers",
          "subscribed": true
        }
      ],
      "created_at": "2026-03-11T08:00:00.000000+00:00",
      "updated_at": "2026-09-30T16:42:10.000000+00:00"
    }
  ]
}
```

**422**

```json
{
  "message": "Validation failed. conditions.groups.0.rules.0.operator: \"greater_than\" does not apply to Email domain.",
  "errors": {
    "conditions.groups.0.rules.0.operator": [
      "\"greater_than\" does not apply to Email domain."
    ]
  }
}
```

---
Source: https://emailit.com/docs/api-reference/segments/preview/

## List segment fields — GET /segments/fields

> List the contact fields, custom fields and audiences that segment rules can use, with the operators and values each one accepts. Alpha: open to the Emailit team only.

# List segment fields

Returns the fields that segment rules can use in this workspace: the contact fields, every custom field (typed by its custom field type), audience membership, purchase data and campaign engagement. Requires an API key with the `full` scope.

`GET /segments/fields`

> **Segments are in alpha:** Segments are open only to the Emailit team while we test them. Other requests, including every request made with an API key, return `403` with `error: "segments_alpha"`. See [Who can use segments](/docs/segments/#who-can-use-segments).

## Returns

- `data` (object[]): One item per field.

- `data[].key` (string): The value to use as a rule's `field`, for example `email_domain` or `custom_fields.plan`.

- `data[].label` (string): Display name. For custom fields, the custom field's name.

- `data[].type` (string): `string`, `number`, `date`, `datetime`, `boolean`, `enum`, `multi`, `audience`, `metric`, `moment`, `purchase`, `view`, `cart`, `coupon` or `campaign_activity`. See [Create a segment](/docs/api-reference/segments/create/#fields). Activity fields such as `purchased` take an object value, see [Activity rules](/docs/api-reference/segments/create/#activity-rules).

- `data[].group` (string): `contact`, `custom_fields`, `audiences`, `commerce` (purchase data) or `engagement` (campaign activity).

- `data[].operators` (string[]): Operators the field accepts.

- `data[].values` (object[]): Allowed values as `value` and `label`: the options of select and multi-select custom fields, `subscribed` and `unsubscribed` for `status`, and the workspace's audiences for `audience`. Absent for other fields.

**Request** `GET /segments/fields`

**cURL**

```bash
curl https://api.emailit.com/v2/segments/fields \
  -H "Authorization: Bearer $EMAILIT_API_KEY"
```

**Node.js**

```javascript
const res = await fetch('https://api.emailit.com/v2/segments/fields', {
  headers: { Authorization: `Bearer ${process.env.EMAILIT_API_KEY}` },
});
const { data: fields } = await res.json();
```

**Python**

```python
import os, requests

r = requests.get(
    "https://api.emailit.com/v2/segments/fields",
    headers={"Authorization": f"Bearer {os.environ['EMAILIT_API_KEY']}"},
)
fields = r.json()["data"]
```

**PHP**

```php
$client = new GuzzleHttp\Client(['base_uri' => 'https://api.emailit.com/v2/']);

$response = $client->get('segments/fields', [
    'headers' => ['Authorization' => 'Bearer ' . getenv('EMAILIT_API_KEY')],
]);
$fields = json_decode($response->getBody(), true)['data'];
```

**200**

```json
{
  "data": [
    {
      "key": "email",
      "label": "Email",
      "type": "string",
      "group": "contact",
      "operators": ["equals", "not_equals", "contains", "not_contains", "starts_with", "ends_with", "in", "not_in", "is_set", "is_not_set"]
    },
    {
      "key": "status",
      "label": "Subscription status",
      "type": "enum",
      "group": "contact",
      "operators": ["equals", "not_equals"],
      "values": [
        { "value": "subscribed", "label": "Subscribed" },
        { "value": "unsubscribed", "label": "Unsubscribed" }
      ]
    },
    {
      "key": "audience",
      "label": "Audience",
      "type": "audience",
      "group": "audiences",
      "operators": ["in", "not_in"],
      "values": [
        { "value": "aud_2nYs8Qm4Hc1Zx7Vb3Ne6Tg9Lk2a", "label": "Customers" }
      ]
    },
    {
      "key": "purchased",
      "label": "Purchased",
      "type": "purchase",
      "group": "commerce",
      "operators": [
        "has",
        "has_not"
      ]
    },
    {
      "key": "custom_fields.renews_on",
      "label": "Renews on",
      "type": "date",
      "group": "custom_fields",
      "operators": ["on", "before", "after", "between", "in_last_days", "more_than_days_ago", "in_next_days", "is_set", "is_not_set"]
    }
  ]
}
```

---
Source: https://emailit.com/docs/api-reference/segments/fields/
