PushMail.dev

Segments

Segments are rule-based dynamic audiences that evaluate at query time. No stale membership data — segments always reflect the current state of your contacts.

Overview

Segments are different from static lists. A list is a manually-curated group of contacts, while a segment is a set of rules that dynamically includes contacts matching the criteria. When you query a segment, the rules are evaluated against your current contact data, so the results are always up to date.

Segments can be used anywhere lists are used: campaign audience targeting, sequence enrollment triggers, and API filtering.

The segment object

{
  "id": 1,
  "siteId": 1,
  "name": "Engaged US Subscribers",
  "description": "Subscribed contacts in the US who opened an email in the last 30 days",
  "rules": {
    "operator": "AND",
    "conditions": [
      { "type": "attribute", "field": "status", "op": "eq", "value": "subscribed" },
      { "type": "attribute", "field": "country", "op": "eq", "value": "US" },
      { "type": "engagement", "metric": "opened", "op": "within_days", "days": 30 }
    ]
  },
  "contactCount": 1250,
  "createdAt": "2026-03-01T10:00:00.000Z",
  "updatedAt": "2026-03-01T10:00:00.000Z"
}

Rules format

Rules use a JSON structure with AND/OR grouping across multiple condition types:

{
  "operator": "AND",
  "conditions": [
    { "type": "attribute", "field": "country", "op": "eq", "value": "US" },
    { "type": "tag", "op": "has", "tagId": 5 },
    { "type": "list", "op": "in", "listId": 3 },
    { "type": "engagement", "metric": "opened", "op": "within_days", "days": 30 },
    { "type": "send_history", "op": "received_campaign", "targetId": 12 },
    {
      "type": "group",
      "operator": "OR",
      "conditions": [
        { "type": "attribute", "field": "city", "op": "eq", "value": "New York" },
        { "type": "attribute", "field": "city", "op": "eq", "value": "San Francisco" }
      ]
    }
  ]
}

Condition types

TypeDescription
attributeMatch contact fields: status, city, country, custom fields, etc.
tagCheck if contact has or doesn't have a specific tag
listCheck if contact is in or not in a specific list
engagementMatch based on email engagement (opened, clicked, bounced, complained)
send_historyMatch based on campaign/sequence history
groupNested AND/OR group for complex logic

Attribute operators

OperatorDescription
eqEquals
neqNot equals
inIn list of values (pass array)
not_inNot in list of values
containsContains substring
starts_withStarts with prefix

Engagement operators

OperatorDescription
within_daysEvent occurred within last N days
not_within_daysEvent did not occur within last N days
neverEvent has never occurred

Send history operators

OperatorDescription
received_campaignContact received a specific campaign
not_received_campaignContact did not receive a specific campaign
completed_sequenceContact completed a specific sequence

Create a segment

POST /v1/segments

ParameterTypeDescription
siteIdrequiredintegerThe site this segment belongs to
namerequiredstringSegment name (max 200 chars)
descriptionstringWhat this segment represents
rulesrequiredobjectRules JSON with operator and conditions
Request
curl -X POST https://pushmail.dev/api/v1/segments \
  -H "Authorization: Bearer pm_live_YOUR_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "siteId": 1,
    "name": "Engaged US Subscribers",
    "description": "Active subscribers in the US with recent opens",
    "rules": {
      "operator": "AND",
      "conditions": [
        { "type": "attribute", "field": "status", "op": "eq", "value": "subscribed" },
        { "type": "attribute", "field": "country", "op": "eq", "value": "US" },
        { "type": "engagement", "metric": "opened", "op": "within_days", "days": 30 }
      ]
    }
  }'
Response
{
  "data": {
    "id": 1,
    "siteId": 1,
    "name": "Engaged US Subscribers",
    "contactCount": 1250,
    "rules": "{...}",
    "createdAt": "2026-03-01T10:00:00.000Z"
  }
}

List segments

GET /v1/segments

ParameterTypeDescription
siteIdrequiredintegerFilter by site (query param)
Request
curl "https://pushmail.dev/api/v1/segments?siteId=1" \
  -H "Authorization: Bearer pm_live_YOUR_KEY"

Get a segment

GET /v1/segments/:id

Returns the segment with a live contact count (re-evaluated at query time).

Request
curl https://pushmail.dev/api/v1/segments/1 \
  -H "Authorization: Bearer pm_live_YOUR_KEY"

Update a segment

PUT /v1/segments/:id

ParameterTypeDescription
namestringNew segment name
descriptionstringNew description
rulesobjectNew rules (contact count is recomputed)
Request
curl -X PUT https://pushmail.dev/api/v1/segments/1 \
  -H "Authorization: Bearer pm_live_YOUR_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "rules": {
      "operator": "AND",
      "conditions": [
        { "type": "attribute", "field": "status", "op": "eq", "value": "subscribed" },
        { "type": "attribute", "field": "country", "op": "in", "value": ["US", "CA", "UK"] }
      ]
    }
  }'

Delete a segment

DELETE /v1/segments/:id

Campaigns referencing this segment will have their segmentId cleared.

Request
curl -X DELETE https://pushmail.dev/api/v1/segments/1 \
  -H "Authorization: Bearer pm_live_YOUR_KEY"

List segment contacts

GET /v1/segments/:id/contacts

Returns paginated contacts matching the segment rules, evaluated live.

ParameterTypeDescription
pageintegerPage number (default: 1)
limitintegerResults per page, 1-100 (default: 50)
Request
curl "https://pushmail.dev/api/v1/segments/1/contacts?page=1&limit=20" \
  -H "Authorization: Bearer pm_live_YOUR_KEY"
Response
{
  "data": {
    "segment": { "id": 1, "name": "Engaged US Subscribers" },
    "contacts": [
      { "id": 42, "email": "jane@example.com", "firstName": "Jane", "status": "subscribed" }
    ],
    "pagination": { "page": 1, "limit": 20, "total": 1250, "totalPages": 63 }
  }
}

Preview count for existing segment

POST /v1/segments/:id/count

Preview the contact count for new rules against an existing segment, without saving changes. Useful for the segment editor UI to show a live count as rules are modified.

Request
curl -X POST https://pushmail.dev/api/v1/segments/1/count \
  -H "Authorization: Bearer pm_live_YOUR_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "rules": {
      "operator": "AND",
      "conditions": [
        { "type": "attribute", "field": "status", "op": "eq", "value": "subscribed" },
        { "type": "attribute", "field": "country", "op": "in", "value": ["US", "CA"] }
      ]
    }
  }'
Response
{
  "data": { "count": 3200 }
}

Preview contact count

POST /v1/segments/preview-count

Preview how many contacts would match a set of rules without creating a segment. Useful for building rules interactively.

Request
curl -X POST https://pushmail.dev/api/v1/segments/preview-count \
  -H "Authorization: Bearer pm_live_YOUR_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "siteId": 1,
    "rules": {
      "operator": "AND",
      "conditions": [
        { "type": "attribute", "field": "status", "op": "eq", "value": "subscribed" }
      ]
    }
  }'
Response
{
  "data": { "count": 5000 }
}

Using segments with campaigns

Pass segmentId when creating a campaign to target a dynamic audience:

Request
curl -X POST https://pushmail.dev/api/v1/campaigns \
  -H "Authorization: Bearer pm_live_YOUR_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "siteId": 1,
    "name": "Re-engagement Campaign",
    "templateId": 10,
    "segmentId": 1
  }'

Using segments with sequences

Set triggerType to segment_enter with the segment ID in triggerConfig:

Request
curl -X POST https://pushmail.dev/api/v1/sequences \
  -H "Authorization: Bearer pm_live_YOUR_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "siteId": 1,
    "name": "Win-back Sequence",
    "triggerType": "segment_enter",
    "triggerConfig": { "segmentId": 1 }
  }'

Next steps

  • Contacts -- Manage your contact records and custom fields
  • Campaigns -- Target segments with one-off email broadcasts
  • Sequences -- Trigger automated drip flows when contacts enter a segment

On this page