Segmentation
Create dynamic contact segments with filter groups, nested logic, and async computation.
Segments let you group contacts based on filters - contact fields, account data, metadata, firmographic attributes, and behavioral events. Segments are computed asynchronously and can be used for targeting in journeys and experiments.
Create a segment
molted segments create \
--name "Enterprise customers in US" \
--filters '{
"logic": "and",
"filters": [
{ "type": "contact_field", "field": "lifecycleStage", "operator": "eq", "value": "customer" },
{ "type": "metadata", "field": "region", "operator": "eq", "value": "us-west" },
{ "type": "firmographic", "field": "companySize", "operator": "gte", "value": 500 }
]
}'| Flag | Type | Required | Description |
|---|---|---|---|
--name | string | Yes | Segment name. |
--filters | JSON | Yes | Filter group as JSON. See filter reference below. |
POST https://api.molted.email/v1/segmentscurl -X POST https://api.molted.email/v1/segments \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"name": "Enterprise customers in US",
"filterGroup": {
"logic": "and",
"filters": [
{ "type": "contact_field", "field": "lifecycleStage", "operator": "eq", "value": "customer" },
{ "type": "metadata", "field": "region", "operator": "eq", "value": "us-west" },
{ "type": "firmographic", "field": "companySize", "operator": "gte", "value": 500 }
]
}
}'| Field | Type | Required | Description |
|---|---|---|---|
name | string | Yes | Segment name. |
filterGroup | object | Yes | Filter group object. See filter reference below. |
Get a segment
molted segments get seg_abc123GET https://api.molted.email/v1/segments/:idcurl "https://api.molted.email/v1/segments/seg_abc123" \
-H "Authorization: Bearer YOUR_API_KEY"List segments
molted segments listGET https://api.molted.email/v1/segmentscurl "https://api.molted.email/v1/segments" \
-H "Authorization: Bearer YOUR_API_KEY"Response
Returns an array of active segments. Archived segments are excluded.
[
{
"id": "seg_abc123",
"tenant_id": "tenant_abc123",
"name": "Enterprise customers in US",
"filter_group": { "logic": "and", "filters": [ "..." ] },
"status": "active",
"contact_count": 142,
"snapshot_version": 3,
"created_at": "2026-03-01T12:00:00Z",
"updated_at": "2026-03-15T08:30:00Z"
}
]If you have no segments yet, the response is an empty array:
[]No segments yet? Create your first segment with molted segments create. See creating segments above for filter syntax and examples.
Update a segment
molted segments update seg_abc123 \
--name "Enterprise US (updated)" \
--filters '{
"logic": "and",
"filters": [
{ "type": "contact_field", "field": "lifecycleStage", "operator": "eq", "value": "customer" },
{ "type": "metadata", "field": "region", "operator": "in", "value": ["us-west", "us-east"] }
]
}'| Flag | Type | Required | Description |
|---|---|---|---|
--name | string | No | Updated segment name. |
--filters | JSON | No | Updated filter group as JSON. |
PATCH https://api.molted.email/v1/segments/:idcurl -X PATCH https://api.molted.email/v1/segments/seg_abc123 \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"name": "Enterprise US (updated)",
"filterGroup": {
"logic": "and",
"filters": [
{ "type": "contact_field", "field": "lifecycleStage", "operator": "eq", "value": "customer" },
{ "type": "metadata", "field": "region", "operator": "in", "value": ["us-west", "us-east"] }
]
}
}'Archive a segment
molted segments archive seg_abc123DELETE https://api.molted.email/v1/segments/:idcurl -X DELETE "https://api.molted.email/v1/segments/seg_abc123" \
-H "Authorization: Bearer YOUR_API_KEY"Compute segment membership
Trigger an async recomputation of the segment's current members. Each computation creates a point-in-time snapshot of matching contacts.
molted segments compute seg_abc123POST https://api.molted.email/v1/segments/:id/computecurl -X POST "https://api.molted.email/v1/segments/seg_abc123/compute" \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{}'List segment members
Results are paginated. Use limit and offset to page through members.
molted segments members seg_abc123 --limit 50 --offset 0| Flag | Type | Required | Description |
|---|---|---|---|
--limit | number | No | Max results per page (default 50). |
--offset | number | No | Pagination offset (default 0). |
GET https://api.molted.email/v1/segments/:id/memberscurl "https://api.molted.email/v1/segments/seg_abc123/members?limit=50&offset=0" \
-H "Authorization: Bearer YOUR_API_KEY"Get contact segments
List all segments a contact belongs to. This is a reverse lookup -- given a contact, it returns every segment they are a member of.
To check whether a contact is in one specific segment instead, use analytics segment-check.
molted segments contact con_abc123GET https://api.molted.email/v1/segments/contact/:contactId/segmentscurl "https://api.molted.email/v1/segments/contact/con_abc123/segments" \
-H "Authorization: Bearer YOUR_API_KEY"Filter types
Each filter has a type that determines which fields you can query.
| Type | Description | Queryable fields |
|---|---|---|
contact_field | Filter on contact properties. | email, name, ownerEmail, lifecycleStage, dealStage |
account_field | Filter on the contact's linked account. | name, domain, plus any key in the account's metadata object |
metadata | Filter on contact custom metadata. | Any key in the contact's metadata object |
firmographic | Filter on account custom metadata. | Any key in the account's metadata object |
behavioral | Filter on event counts within a time window. | Uses behavioralWindow - see behavioral filters below |
Standard filter structure
{
"type": "contact_field",
"field": "lifecycleStage",
"operator": "eq",
"value": "customer"
}| Field | Type | Required | Description |
|---|---|---|---|
type | string | Yes | One of: contact_field, account_field, metadata, firmographic, behavioral. |
field | string | Yes | The field to filter on. Valid fields depend on the type. |
operator | string | Yes | Comparison operator. See operators below. |
value | any | Varies | The value to compare against. Not required for exists/not_exists. |
Behavioral filters
Behavioral filters count how many times an event occurred within a time window. They use a behavioralWindow object instead of a simple value.
{
"type": "behavioral",
"field": "event_count",
"operator": "gte",
"value": 0,
"behavioralWindow": {
"eventName": "email_opened",
"windowDays": 30,
"countOperator": "gte",
"countValue": 3
}
}| Field | Type | Required | Description |
|---|---|---|---|
behavioralWindow.eventName | string | Yes | The event to count (e.g. email_opened, email_clicked, email_sent). |
behavioralWindow.windowDays | number | Yes | Lookback window in days. Maximum 90. |
behavioralWindow.countOperator | string | Yes | Operator to apply to the event count (e.g. gte, eq, lt). |
behavioralWindow.countValue | number | Yes | The threshold count to compare against. |
This example matches contacts who opened an email 3 or more times in the last 30 days.
Operators
| Operator | Value type | Description | Example value |
|---|---|---|---|
eq | any | Equals. | "pro", 500, true |
neq | any | Not equals. | "free" |
gt | number | Greater than. | 100 |
gte | number | Greater than or equal. | 500 |
lt | number | Less than. | 50 |
lte | number | Less than or equal. | 1000 |
contains | string | String contains substring. | "example.com" |
not_contains | string | String does not contain substring. | "test" |
in | array | Value is in the provided list. | ["us-west", "us-east"] |
not_in | array | Value is not in the provided list. | ["spam", "bounced"] |
exists | none | Field exists and is not null. No value needed. | - |
not_exists | none | Field does not exist or is null. No value needed. | - |
between | array | Value is between two bounds (inclusive). | [100, 500] |
Type constraints: gt, gte, lt, lte, and between only work with numeric values. contains and not_contains only work with strings. Using an operator with the wrong value type returns no matches.
Filter group structure
A filter group wraps one or more filters with a logic operator.
{
"logic": "and",
"filters": [
{ "type": "contact_field", "field": "lifecycleStage", "operator": "eq", "value": "customer" },
{ "type": "metadata", "field": "region", "operator": "eq", "value": "us-west" }
]
}| Field | Type | Required | Description |
|---|---|---|---|
logic | string | Yes | and or or. Determines how filters are combined. |
filters | array | Yes | Array of filters or nested filter groups. |
Nested logic
Filter groups can contain other filter groups for complex AND/OR logic:
{
"logic": "or",
"filters": [
{
"logic": "and",
"filters": [
{ "type": "contact_field", "field": "lifecycleStage", "operator": "eq", "value": "lead" },
{
"type": "behavioral",
"field": "event_count",
"operator": "gte",
"value": 0,
"behavioralWindow": {
"eventName": "email_opened",
"windowDays": 30,
"countOperator": "gte",
"countValue": 3
}
}
]
},
{
"logic": "and",
"filters": [
{ "type": "contact_field", "field": "lifecycleStage", "operator": "eq", "value": "customer" },
{ "type": "metadata", "field": "plan", "operator": "eq", "value": "enterprise" }
]
}
]
}This matches contacts who are either (leads with 3+ email opens in the last 30 days) OR (enterprise customers). Nesting depth is unlimited.