Segments API
Create and manage dynamic user segments programmatically.
All endpoints on this page are relative to the base URL: https://api-eu1.joryio.com - see API Overview.
Authentication
All requests require API key authentication:
Authorization: Bearer jry_live_your_api_key_here
Content-Type: application/json
Create Segment
Create a new user segment with filters.
Endpoint
POST /segments
Request Body
| Field | Type | Required | Description |
|---|---|---|---|
name | string | Yes | Segment name (max 255 chars) |
description | string | No | Segment description (max 1000 chars) |
filterGroups | array | Yes | Array of filter groups (max 20) |
excludeFilterGroups | array | No | Users matching any of these groups are removed (max 20) |
groupOperator | string | Yes | How to combine groups: AND or OR |
tags | array | No | Tag names for organizing segments |
Filter Structure
Each filter group contains up to 50 filters:
{
filters: [
{
type: 'attribute' | 'default_attribute' | 'event' | 'ecommerce'
| 'behavioral' | 'segment' | 'canvas_execution'
| 'list_membership' | 'channel_subscription' | 'app'
| 'entity' | 'bounce_status' | 'wallet_pass',
field?: string, // For attribute filters
operator: string, // See Filter Operators below
value?: any, // Comparison value (also carries N for count operators)
eventName?: string, // For event filters
withinDays?: number, // Time window for event filters
startDate?: string, // Absolute window start (ISO 8601, event filters)
endDate?: string, // Absolute window end (ISO 8601, event filters)
segmentId?: string, // For segment filters
listId?: string, // For list_membership filters
channel?: string // For channel_subscription filters
}
],
operator: 'AND' | 'OR'
}
Example Request - Simple Attribute Filter
curl -X POST https://api-eu1.joryio.com/segments \
-H "Authorization: Bearer jry_live_your_api_key" \
-H "Content-Type: application/json" \
-d '{
"name": "Premium Users",
"description": "Users on premium plan",
"filterGroups": [
{
"filters": [
{
"type": "attribute",
"field": "plan",
"operator": "equals",
"value": "premium"
}
],
"operator": "AND"
}
],
"groupOperator": "AND"
}'
Example Request - Behavioral Segment
curl -X POST https://api-eu1.joryio.com/segments \
-H "Authorization: Bearer jry_live_your_api_key" \
-H "Content-Type: application/json" \
-d '{
"name": "Active Trial Users",
"description": "Trial users active in last 7 days",
"filterGroups": [
{
"filters": [
{
"type": "attribute",
"field": "plan",
"operator": "equals",
"value": "trial"
},
{
"type": "event",
"eventName": "Session Started",
"operator": "performed",
"withinDays": 7
}
],
"operator": "AND"
}
],
"groupOperator": "AND"
}'
Example Request - Complex Segment
curl -X POST https://api-eu1.joryio.com/segments \
-H "Authorization: Bearer jry_live_your_api_key" \
-H "Content-Type: application/json" \
-d '{
"name": "High-Value At-Risk Users",
"description": "Paid users with high LTV who haven'\''t logged in recently",
"filterGroups": [
{
"filters": [
{
"type": "attribute",
"field": "plan",
"operator": "in",
"value": ["premium", "enterprise"]
},
{
"type": "attribute",
"field": "lifetimeValue",
"operator": "gte",
"value": 500
}
],
"operator": "AND"
},
{
"filters": [
{
"type": "event",
"eventName": "Login",
"operator": "not_performed",
"withinDays": 14
}
],
"operator": "AND"
}
],
"groupOperator": "AND"
}'
Response
The segment object is returned directly (no wrapper envelope). Segment IDs are UUIDs. Member counts are not stored on the segment - use GET /segments/:id/size:
{
"id": "3f9d2c1e-7a54-4b2e-9c1d-8e6f5a4b3c2d",
"name": "Premium Users",
"description": "Users on premium plan",
"filterGroups": [
{
"filters": [
{
"type": "attribute",
"field": "plan",
"operator": "equals",
"value": "premium"
}
],
"operator": "AND"
}
],
"excludeFilterGroups": [],
"groupOperator": "AND",
"tags": [],
"status": "active",
"createdAt": "2024-01-20T10:30:00.000Z",
"updatedAt": "2024-01-20T10:30:00.000Z"
}
Get Segment
Retrieve segment details.
Endpoint
GET /segments/:id
Path Parameters
| Parameter | Type | Description |
|---|---|---|
id | string | Segment ID |
Example Request
curl -X GET https://api-eu1.joryio.com/segments/3f9d2c1e-7a54-4b2e-9c1d-8e6f5a4b3c2d \
-H "Authorization: Bearer jry_live_your_api_key"
Response
The segment object, returned directly (for the current member count, call GET /segments/:id/size):
{
"id": "3f9d2c1e-7a54-4b2e-9c1d-8e6f5a4b3c2d",
"name": "Premium Users",
"description": "Users on premium plan",
"filterGroups": [...],
"excludeFilterGroups": [],
"groupOperator": "AND",
"tags": [],
"status": "active",
"createdAt": "2024-01-20T10:30:00.000Z",
"updatedAt": "2024-01-20T10:30:00.000Z"
}
List Segments
Get all segments with pagination.
Endpoint
GET /segments
Query Parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
limit | number | 100 | Results per page (max 100) |
offset | number | 0 | Number of segments to skip |
q | string | - | Free-text search on segment name |
status | string | - | Filter by status: active or archived |
tags | string | - | Comma-separated tag names |
createdBy | string | - | Comma-separated creator user IDs |
editedBy | string | - | Comma-separated last-editor user IDs |
Example Request
curl -X GET "https://api-eu1.joryio.com/segments?limit=50&status=active" \
-H "Authorization: Bearer jry_live_your_api_key"
Response
{
"data": [
{
"id": "3f9d2c1e-7a54-4b2e-9c1d-8e6f5a4b3c2d",
"name": "Premium Users",
"status": "active",
"createdAt": "2024-01-20T10:30:00.000Z"
},
{
"id": "9a8b7c6d-5e4f-4a3b-8c2d-1e0f9a8b7c6d",
"name": "Trial Users",
"status": "active",
"createdAt": "2024-01-19T09:15:00.000Z"
}
],
"pagination": {
"total": 23,
"page": 1,
"limit": 50,
"offset": 0,
"totalPages": 1,
"hasMore": false
}
}
Update Segment
Update segment name, description, or filters. Uses PUT (there is no PATCH route); fields you omit are left unchanged.
Endpoint
PUT /segments/:id
Request Body
{
"name": "Updated Name",
"description": "Updated description",
"filterGroups": [...]
}
Example Request
curl -X PUT https://api-eu1.joryio.com/segments/3f9d2c1e-7a54-4b2e-9c1d-8e6f5a4b3c2d \
-H "Authorization: Bearer jry_live_your_api_key" \
-H "Content-Type: application/json" \
-d '{
"description": "Premium users who have made at least one purchase"
}'
Response
The updated segment object, returned directly:
{
"id": "3f9d2c1e-7a54-4b2e-9c1d-8e6f5a4b3c2d",
"name": "Premium Users",
"description": "Premium users who have made at least one purchase",
"status": "active",
"updatedAt": "2024-01-21T14:30:00.000Z"
}
Archive Segment
Segments cannot be hard-deleted - campaigns and journeys hold segment references, so removal is archive-only. Archived segments stop appearing in active lists and can be restored at any time.
Endpoints
POST /segments/:id/archive
POST /segments/:id/unarchive
Example Request
curl -X POST https://api-eu1.joryio.com/segments/3f9d2c1e-7a54-4b2e-9c1d-8e6f5a4b3c2d/archive \
-H "Authorization: Bearer jry_live_your_api_key"
Response
The segment object with its new status:
{
"id": "3f9d2c1e-7a54-4b2e-9c1d-8e6f5a4b3c2d",
"name": "Premium Users",
"status": "archived",
"updatedAt": "2024-01-21T14:30:00.000Z"
}
Notes
- Archiving a segment doesn't delete the users in it
- Active campaigns using this segment will be affected
- Use
POST /segments/:id/unarchiveto restore
Get Segment Users
Get list of users in a segment.
Endpoint
GET /segments/:id/users
Query Parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
limit | number | 100 | Number of users to return |
offset | number | 0 | Number of users to skip |
Example Request
curl -X GET "https://api-eu1.joryio.com/segments/3f9d2c1e-7a54-4b2e-9c1d-8e6f5a4b3c2d/users?limit=100" \
-H "Authorization: Bearer jry_live_your_api_key"
Response
A bare JSON array of user documents (no pagination envelope - page with limit / offset):
[
{
"_id": "665f1e2a9b3c4d5e6f7a8b9c",
"externalId": "user_123",
"email": "user1@example.com",
"attributes": {
"plan": "premium",
"signupDate": "2024-01-15"
}
},
{
"_id": "665f1e2a9b3c4d5e6f7a8b9d",
"externalId": "user_456",
"email": "user2@example.com",
"attributes": {
"plan": "premium",
"signupDate": "2024-01-18"
}
}
]
Get Segment Size
Get the current number of users in a segment. By default this is a fast approximate estimate; pass ?exact=true for a precise count. The size number is the only thing that is ever approximate - actual membership and sends are always exact.
Endpoint
GET /segments/:id/size
Query Parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
exact | boolean | false | true returns the precise count (slower on large workspaces) |
Example Request
curl -X GET https://api-eu1.joryio.com/segments/3f9d2c1e-7a54-4b2e-9c1d-8e6f5a4b3c2d/size \
-H "Authorization: Bearer jry_live_your_api_key"
Response
{
"segmentId": "3f9d2c1e-7a54-4b2e-9c1d-8e6f5a4b3c2d",
"size": 1234,
"approximate": true
}
Filter Operators
Attribute Operators
| Operator | Description | Example |
|---|---|---|
equals | Exact match | plan equals "premium" |
not_equals | Not equal | plan not_equals "free" |
in | Value in list | plan in ["premium", "enterprise"] |
not_in | Value not in list | plan not_in ["free", "trial"] |
contains | String contains | email contains "@company.com" |
not_contains | String doesn't contain | email not_contains "@competitor.com" |
gt | Greater than | lifetimeValue > 1000 |
gte | Greater than or equal | age >= 18 |
lt | Less than | loginCount < 5 |
lte | Less than or equal | mrr <= 99 |
exists | Field exists | phone exists |
not_exists | Field doesn't exist | referralCode not_exists |
within_next_days | Date within next N days | trialEndsDate within_next_days 7 |
Event Operators
| Operator | Description | Example |
|---|---|---|
performed | User performed event | Performed "Order Completed" |
not_performed | User didn't perform event | Not performed "Onboarding Completed" |
performed_count_gte | Event count greater than or equal (N in value) | Performed "Login" >= 10 times |
performed_count_lte | Event count less than or equal (N in value) | Performed "Login" <= 5 times |
performed_in_last_days | Performed within the last N days (N in value) | Performed "Login" in last 7 days |
not_performed_in_last_days | Not performed within the last N days (N in value) | No "Login" in last 14 days |
Filter Examples
Attribute Filters
// String matching
{
"type": "attribute",
"field": "email",
"operator": "contains",
"value": "@company.com"
}
// Numeric comparison
{
"type": "attribute",
"field": "lifetimeValue",
"operator": "gte",
"value": 500
}
// Multiple values
{
"type": "attribute",
"field": "plan",
"operator": "in",
"value": ["premium", "enterprise"]
}
// Field exists
{
"type": "attribute",
"field": "phone",
"operator": "exists"
}
// Date within next N days (future dates)
{
"type": "attribute",
"field": "trialEndsDate",
"operator": "within_next_days",
"value": 7
}
Event Filters
// Event performed within timeframe
{
"type": "event",
"eventName": "Order Completed",
"operator": "performed",
"withinDays": 30
}
// Event not performed
{
"type": "event",
"eventName": "Onboarding Completed",
"operator": "not_performed"
}
// Event count (N goes in `value`)
{
"type": "event",
"eventName": "Login",
"operator": "performed_count_gte",
"value": 10,
"withinDays": 30
}
Segment Filters
// User in another segment
{
"type": "segment",
"segmentId": "9a8b7c6d-5e4f-4a3b-8c2d-1e0f9a8b7c6d",
"operator": "in_segment"
}
// User not in another segment
{
"type": "segment",
"segmentId": "9a8b7c6d-5e4f-4a3b-8c2d-1e0f9a8b7c6d",
"operator": "not_in_segment"
}
Common Segment Examples
Trial Conversion Opportunity
{
"name": "Trial Expiring Soon",
"description": "Users whose trial ends in the next 3 days and haven't purchased",
"filterGroups": [
{
"filters": [
{
"type": "attribute",
"field": "plan",
"operator": "equals",
"value": "trial"
},
{
"type": "attribute",
"field": "trialEndsDate",
"operator": "within_next_days",
"value": 3
},
{
"type": "event",
"eventName": "Order Completed",
"operator": "not_performed"
}
],
"operator": "AND"
}
],
"groupOperator": "AND"
}
Power Users
{
"name": "Power Users",
"filterGroups": [
{
"filters": [
{
"type": "event",
"eventName": "Login",
"operator": "performed_count_gte",
"value": 20,
"withinDays": 30
},
{
"type": "event",
"eventName": "Feature Used",
"operator": "performed_count_gte",
"value": 50,
"withinDays": 30
}
],
"operator": "AND"
}
],
"groupOperator": "AND"
}
At-Risk Customers
{
"name": "At-Risk Premium Users",
"filterGroups": [
{
"filters": [
{
"type": "attribute",
"field": "plan",
"operator": "in",
"value": ["premium", "enterprise"]
},
{
"type": "attribute",
"field": "lifetimeValue",
"operator": "gte",
"value": 500
}
],
"operator": "AND"
},
{
"filters": [
{
"type": "event",
"eventName": "Login",
"operator": "not_performed",
"withinDays": 14
}
],
"operator": "AND"
}
],
"groupOperator": "AND"
}
Dynamic Updates
Segments are dynamic: membership is not a stored list - the segment's filters are evaluated against current profile and event data whenever the segment is used (campaign targeting, journey gates, membership checks). There is nothing to refresh or recompute via the API.
Checking Segment Size
# Get current size (approximate by default; add ?exact=true for a precise count)
curl -X GET https://api-eu1.joryio.com/segments/3f9d2c1e-7a54-4b2e-9c1d-8e6f5a4b3c2d/size \
-H "Authorization: Bearer jry_live_your_api_key"
Error Responses
All errors use the standard error body - see API Overview: Error Response.
400 Bad Request - Invalid Filter
{
"statusCode": 400,
"message": "Bad Request Exception",
"timestamp": "2026-01-15T10:30:00.000Z",
"path": "/segments",
"errors": [
"filterGroups.0.filters.0.operator must be one of the following values: equals, not_equals, contains, ..."
]
}
404 Not Found
{
"statusCode": 404,
"message": "Segment with ID 3f9d2c1e-7a54-4b2e-9c1d-8e6f5a4b3c2d not found",
"timestamp": "2026-01-15T10:30:00.000Z",
"path": "/segments/3f9d2c1e-7a54-4b2e-9c1d-8e6f5a4b3c2d"
}
Rate Limits
The Segments API has no fixed per-endpoint rate limits today - see API Overview: Rate Limiting.
Best Practices
1. Keep Segments Focused
Good: Specific, targeted segments
{
"name": "Premium US Users - Active Last 7 Days",
"filters": [...]
}
Bad: Overly broad segments
{
"name": "All Users",
"filters": []
}
2. Use Descriptive Names
Good: Self-explanatory names
- "Trial Users - Expiring This Week"
- "High-Value At-Risk Customers"
- "New Signups - Not Onboarded"
Bad: Unclear names
- "Segment 1"
- "Test"
- "Users ABC"
3. Combine Filters Logically
Use AND for narrowing, OR for broadening:
// AND: Premium users who are active
{
"filters": [
{ "field": "plan", "operator": "equals", "value": "premium" },
{ "eventName": "Login", "operator": "performed", "withinDays": 7 }
],
"operator": "AND"
}
// OR: Users on any paid plan
{
"filters": [
{ "field": "plan", "operator": "equals", "value": "premium" },
{ "field": "plan", "operator": "equals", "value": "enterprise" }
],
"operator": "OR"
}
4. Monitor Segment Size
Track segment size over time:
// Poll segment size
setInterval(async () => {
const { size, approximate } = await fetch(`/segments/${segmentId}/size`).then(r => r.json());
console.log(`Segment size: ${approximate ? '≈' : ''}${size}`);
}, 60000); // Every minute