Segments
Create dynamic segments based on subscriber attributes and behavior
Segments are dynamic subscriber groups defined by conditions. Unlike static lists, segments automatically update as subscriber data changes. Use segments to target campaigns at specific audiences based on attributes, engagement, and behavior.
Match Types
| Match Type | Value | Description |
|---|---|---|
All | 0 | All conditions must match (AND logic) |
Any | 1 | Any condition can match (OR logic) |
Create a Segment
POST https://api.mail.land/v1/marketing/segments{
"name": "Active Engaged Users",
"description": "Users who opened or clicked in last 30 days",
"matchType": "All",
"conditions": [
{
"field": "lastemailopenedat",
"operator": "inlast",
"value": "30"
},
{
"field": "status",
"operator": "equals",
"value": "Active"
}
]
}| Field | Type | Required | Description |
|---|---|---|---|
name | string | Yes | Segment name (unique per workspace) |
description | string | No | Segment description |
matchType | string | No | All (default) or Any |
conditions | array | Yes | At least one condition |
curl -X POST https://api.mail.land/v1/marketing/segments \
-H "Authorization: Bearer eyJhbGciOiJIUzI1NiIs..." \
-H "Content-Type: application/json" \
-d '{
"name": "Active Engaged Users",
"matchType": "All",
"conditions": [
{ "field": "lastemailopenedat", "operator": "inlast", "value": "30" },
{ "field": "status", "operator": "equals", "value": "Active" }
]
}'Response
{
"id": "0qe306asbapwvd",
"name": "Active Engaged Users",
"description": "Users who opened or clicked in last 30 days",
"matchType": "all",
"matchTypeName": "All",
"conditionsCount": 2,
"subscriberCount": 450,
"createdAt": "2026-02-17T12:00:00Z",
"updatedAt": "2026-02-17T12:00:00Z"
}Responses return matchType in lowercase ("all" / "any") even though the create/update request accepts "All"/"Any".
Condition fields based on opens/clicks (emailsopened, lastemailopenedat, etc.) include machine activity, Apple Mail Privacy Protection prefetch and security link scanners, which is not filtered out today.
An undocumented GET /{id}/preview endpoint also exists, returning a sample of subscribers who currently match the segment's conditions.
Condition Fields
String Fields
Fields: email, firstname, lastname, company, source, phone
| Operator | Description | Value Required |
|---|---|---|
equals | Exact match | Yes |
notequals | Not equal | Yes |
contains | Contains substring | Yes |
notcontains | Does not contain | Yes |
startswith | Starts with | Yes |
endswith | Ends with | Yes |
isempty | Field is empty | No |
isnotempty | Field is not empty | No |
Numeric Fields
Fields: emailssent, emailsopened, emailsclicked
| Operator | Description | Value Required | Value2 Required |
|---|---|---|---|
equals | Equal to | Yes | No |
notequals | Not equal | Yes | No |
greaterthan | Greater than | Yes | No |
greaterthanorequal | Greater or equal | Yes | No |
lessthan | Less than | Yes | No |
lessthanorequal | Less or equal | Yes | No |
between | Between two values | Yes | Yes |
Date Fields
Fields: createdat, subscribedat, lastemailsentat, lastemailopenedat, lastemailclickedat
| Operator | Description | Value Required |
|---|---|---|
equals | On specific date | Yes (ISO date) |
before | Before date | Yes (ISO date) |
after | After date | Yes (ISO date) |
onorbefore | On or before | Yes (ISO date) |
onorafter | On or after | Yes (ISO date) |
between | Between dates | Yes (value + value2) |
inlast | In the last N days | Yes (integer days) |
isnull | Date not set | No |
isnotnull | Date is set | No |
Enum Fields
Field: status
| Operator | Description | Values |
|---|---|---|
equals | Equal to status | Active, Unsubscribed, Bounced, Complained |
notequals | Not equal to | Same values |
Condition Examples
{ "field": "email", "operator": "contains", "value": "example.com" }{ "field": "emailssent", "operator": "between", "value": "10", "value2": "50" }{ "field": "lastemailclickedat", "operator": "inlast", "value": "7" }{ "field": "firstname", "operator": "isempty" }Get Segment Metadata
Retrieve all available fields, operators, and enum values for building segment conditions:
GET https://api.mail.land/v1/marketing/segments/metadata/fieldscurl https://api.mail.land/v1/marketing/segments/metadata/fields \
-H "Authorization: Bearer eyJhbGciOiJIUzI1NiIs..."{
"fields": [
{
"name": "email",
"label": "Email",
"type": "string",
"operators": ["equals", "notequals", "contains", "notcontains", "startswith", "endswith", "isempty", "isnotempty"],
"enumValues": null
},
{
"name": "status",
"label": "Status",
"type": "enum",
"operators": ["equals", "notequals"],
"enumValues": ["Active", "Unsubscribed", "Bounced", "Complained"]
}
]
}List Segments
GET https://api.mail.land/v1/marketing/segments| Parameter | Type | Default | Description |
|---|---|---|---|
cursor | string | - | Opaque cursor from the previous page's nextCursor. Omit for the first page. |
limit | int | 20 | Items per page |
search | string | - | Search by name or description |
sortBy | string | - | Sort field |
sortDesc | bool | false | Sort descending |
curl "https://api.mail.land/v1/marketing/segments?limit=20" \
-H "Authorization: Bearer eyJhbGciOiJIUzI1NiIs..."Get Segment Details
GET https://api.mail.land/v1/marketing/segments/{id}Returns the full segment with conditions:
curl https://api.mail.land/v1/marketing/segments/0qe306asbapwvd \
-H "Authorization: Bearer eyJhbGciOiJIUzI1NiIs..."{
"id": "0qe306asbapwvd",
"name": "Active Engaged Users",
"description": "Users who engaged in last 30 days",
"matchType": "all",
"matchTypeName": "All",
"conditionsCount": 2,
"subscriberCount": 450,
"conditions": [
{
"field": "lastemailopenedat",
"operator": "inlast",
"value": "30",
"value2": null
},
{
"field": "status",
"operator": "equals",
"value": "Active",
"value2": null
}
],
"cachedCount": 450,
"cachedAt": "2026-02-17T10:00:00Z",
"createdAt": "2026-01-10T08:00:00Z",
"updatedAt": "2026-02-17T10:00:00Z"
}Preview Conditions
Preview the result of conditions before creating a segment. Segment evaluation always restricts to
Active subscribers, so a condition like status notequals Active matches nobody.
POST https://api.mail.land/v1/marketing/segments/preview{
"conditions": [
{ "field": "lastemailopenedat", "operator": "inlast", "value": "30" }
],
"matchType": "All"
}curl -X POST https://api.mail.land/v1/marketing/segments/preview \
-H "Authorization: Bearer eyJhbGciOiJIUzI1NiIs..." \
-H "Content-Type: application/json" \
-d '{
"conditions": [
{ "field": "lastemailopenedat", "operator": "inlast", "value": "30" }
],
"matchType": "All"
}'{
"count": 450,
"sampleEmails": [
"[email protected]",
"[email protected]",
"[email protected]"
]
}Get Segment Count
GET https://api.mail.land/v1/marketing/segments/{id}/countcurl https://api.mail.land/v1/marketing/segments/0qe306asbapwvd/count \
-H "Authorization: Bearer eyJhbGciOiJIUzI1NiIs..."{
"segmentId": "0qe306asbapwvd",
"count": 450
}Refresh Segment Cache
Force a re-count of matching subscribers:
POST https://api.mail.land/v1/marketing/segments/{id}/refreshcurl -X POST https://api.mail.land/v1/marketing/segments/0qe306asbapwvd/refresh \
-H "Authorization: Bearer eyJhbGciOiJIUzI1NiIs..."{
"segmentId": "0qe306asbapwvd",
"count": 460,
"refreshedAt": "2026-02-17T12:30:00Z"
}Duplicate a Segment
POST https://api.mail.land/v1/marketing/segments/{id}/duplicate?name=Copy%20of%20SegmentCreates a new segment with cloned conditions. The name parameter is optional.
curl -X POST "https://api.mail.land/v1/marketing/segments/0qe306asbapwvd/duplicate?name=Copy%20of%20Segment" \
-H "Authorization: Bearer eyJhbGciOiJIUzI1NiIs..."Update a Segment
PUT https://api.mail.land/v1/marketing/segments/{id}The request body matches the create request. Updating a segment automatically refreshes its cached count.
curl -X PUT https://api.mail.land/v1/marketing/segments/0qe306asbapwvd \
-H "Authorization: Bearer eyJhbGciOiJIUzI1NiIs..." \
-H "Content-Type: application/json" \
-d '{
"name": "Active Engaged Users (Updated)",
"matchType": "All",
"conditions": [
{ "field": "lastemailopenedat", "operator": "inlast", "value": "14" },
{ "field": "status", "operator": "equals", "value": "Active" }
]
}'Delete a Segment
DELETE https://api.mail.land/v1/marketing/segments/{id}Deleting a segment detaches it from any Draft or Scheduled campaign that targets it (the campaign's
segmentId is cleared), which then has no audience: sending it returns 422 or delivers to
nobody. A campaign that is already Sending is unaffected, because its recipients were already
resolved.
curl -X DELETE https://api.mail.land/v1/marketing/segments/0qe306asbapwvd \
-H "Authorization: Bearer eyJhbGciOiJIUzI1NiIs..."Error Responses
| Status | Code | Description |
|---|---|---|
400 | VALIDATION_FAILED | Name or conditions invalid |
400 | INVALID_REQUEST | Segment name already exists |
403 | FORBIDDEN | Insufficient permissions |
404 | RESOURCE_NOT_FOUND | Segment not found |
Next Steps
- Campaigns: target campaigns with segments
- Automations: automations do not currently trigger on segment membership
- Subscribers: manage the contacts in your segments