A segment is an audience defined by rules instead of by hand: a contact is in it because it matches. Membership is worked out on the server, so a segment stays up to date as contacts change. Use segments to target campaigns; for a hand-filled audience use contact lists.
Rules ​
Each rule is { "field", "operator", "value" }, every part a string, and the whole set is sent as one serialised JSON string in expressionsJson.
| Allowed values | |
|---|---|
field |
status, email, phone, externalId, displayName, or a custom contact attribute as contact.attr.<key> or the short form attr.<key>. The older external_id, display_name and the legacy aliases first_name, firstName, last_name and lastName still work; the name aliases map to displayName. |
operator |
EQ, NE, CONTAINS, IS_NULL, IS_NOT_NULL, and — for custom attributes only — GT, LT, GTE and LTE |
Operators are case-insensitive, and a rule with no operator defaults to EQ. Any other field or operator is rejected when you save.
Endpoints
GET/segmentsList segmentsGET/segments/{segmentId}Retrieve a segmentPOST/segmentsCreate a segmentPUT/segments/{segmentId}Update a segmentDELETE/segments/{segmentId}Delete a segmentGET/segments/{segmentId}/previewPreview a segment’s contactsThe segment object
Attributes
idintegerUnique identifier of the segment.namestringSegment name.descriptionstringnullableWhat the segment is for.expressionsJsonstringnullableThe rules, as a serialised JSON array of{ "field", "operator", "value" }objects. All three are strings;valuemay benullfor the null operators. See Rules at the top of this page.matchCountintegernullableHow many contacts match. This is a cached figure refreshed on a schedule, so it can lag behind your contacts — read it together withmatchCountUpdatedAt.matchCountUpdatedAtstringnullableWhenmatchCountwas last recomputed (ISO 8601).
{
"id": 12,
"name": "Gold customers with email",
"description": "Customers on the Gold plan we can email",
"expressionsJson": "[{\"field\":\"status\",\"operator\":\"EQ\",\"value\":\"customer\"},{\"field\":\"contact.attr.plan\",\"operator\":\"EQ\",\"value\":\"gold\"},{\"field\":\"email\",\"operator\":\"IS_NOT_NULL\",\"value\":null}]",
"matchCount": 342,
"matchCountUpdatedAt": "2026-11-07T02:00:00Z"
}
List segments
Returns every segment in your organisation as a plain array. This list is not paginated.
contacts:readReturns
200The segment object.
curl -X GET "https://api.cx.na6iq.com/api/v1/segments" \
-H "Authorization: Bearer $NATIQ_TOKEN"
const res = await fetch('https://api.cx.na6iq.com/api/v1/segments', {
method: 'GET',
headers: {
Authorization: `Bearer ${process.env.NATIQ_TOKEN}`,
},
})
if (!res.ok) throw new Error((await res.json().catch(() => ({}))).error?.message ?? `HTTP ${res.status}`)
const data = await res.json()
import os, requests
res = requests.get(
"https://api.cx.na6iq.com/api/v1/segments",
headers={"Authorization": f"Bearer {os.environ['NATIQ_TOKEN']}"},
)
res.raise_for_status()
data = res.json()
[
{
"id": 12,
"name": "Gold customers with email",
"description": "Customers on the Gold plan we can email",
"expressionsJson": "[{\"field\":\"status\",\"operator\":\"EQ\",\"value\":\"customer\"},{\"field\":\"contact.attr.plan\",\"operator\":\"EQ\",\"value\":\"gold\"},{\"field\":\"email\",\"operator\":\"IS_NOT_NULL\",\"value\":null}]",
"matchCount": 342,
"matchCountUpdatedAt": "2026-11-07T02:00:00Z"
}
]
Retrieve a segment
Returns one segment with its rules.
contacts:readPath parameters
segmentIdintegerrequiredThe segment’sid.
Returns
200The segment object.
Errors
- 404
SEGMENT_NOT_FOUNDNo segment with this ID in your organisation.
curl -X GET "https://api.cx.na6iq.com/api/v1/segments/42" \
-H "Authorization: Bearer $NATIQ_TOKEN"
const res = await fetch('https://api.cx.na6iq.com/api/v1/segments/42', {
method: 'GET',
headers: {
Authorization: `Bearer ${process.env.NATIQ_TOKEN}`,
},
})
if (!res.ok) throw new Error((await res.json().catch(() => ({}))).error?.message ?? `HTTP ${res.status}`)
const data = await res.json()
import os, requests
res = requests.get(
"https://api.cx.na6iq.com/api/v1/segments/42",
headers={"Authorization": f"Bearer {os.environ['NATIQ_TOKEN']}"},
)
res.raise_for_status()
data = res.json()
{
"id": 12,
"name": "Gold customers with email",
"description": "Customers on the Gold plan we can email",
"expressionsJson": "[{\"field\":\"status\",\"operator\":\"EQ\",\"value\":\"customer\"},{\"field\":\"contact.attr.plan\",\"operator\":\"EQ\",\"value\":\"gold\"},{\"field\":\"email\",\"operator\":\"IS_NOT_NULL\",\"value\":null}]",
"matchCount": 342,
"matchCountUpdatedAt": "2026-11-07T02:00:00Z"
}
Create a segment
Creates a segment. matchCount is calculated as part of the call.
contacts:writeRequest body
namestringrequiredSegment name.descriptionstringnullableOptional description. Replaced on update: omit it and it is cleared.expressionsJsonstringrequiredThe rules as a serialised JSON array. See Rules at the top of this page.
Returns
201The segment object.
Errors
- 400
VALIDATION_FAILED`name` or `expressionsJson` is blank, or `description` is longer than 2000 characters. - 400
INVALID_REQUESTThe rules use a field or operator that is not supported. Bad rules are rejected when you save, because the count runs at save.
curl -X POST "https://api.cx.na6iq.com/api/v1/segments" \
-H "Authorization: Bearer $NATIQ_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"name": "Gold customers with email",
"description": "Customers on the Gold plan we can email",
"expressionsJson": "[{\"field\":\"status\",\"operator\":\"EQ\",\"value\":\"customer\"},{\"field\":\"contact.attr.plan\",\"operator\":\"EQ\",\"value\":\"gold\"},{\"field\":\"email\",\"operator\":\"IS_NOT_NULL\",\"value\":null}]"
}'
const res = await fetch('https://api.cx.na6iq.com/api/v1/segments', {
method: 'POST',
headers: {
Authorization: `Bearer ${process.env.NATIQ_TOKEN}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({
"name": "Gold customers with email",
"description": "Customers on the Gold plan we can email",
"expressionsJson": "[{\"field\":\"status\",\"operator\":\"EQ\",\"value\":\"customer\"},{\"field\":\"contact.attr.plan\",\"operator\":\"EQ\",\"value\":\"gold\"},{\"field\":\"email\",\"operator\":\"IS_NOT_NULL\",\"value\":null}]"
}),
})
if (!res.ok) throw new Error((await res.json().catch(() => ({}))).error?.message ?? `HTTP ${res.status}`)
const data = await res.json()
import os, requests
res = requests.post(
"https://api.cx.na6iq.com/api/v1/segments",
headers={"Authorization": f"Bearer {os.environ['NATIQ_TOKEN']}"},
json={
"name": "Gold customers with email",
"description": "Customers on the Gold plan we can email",
"expressionsJson": "[{\"field\":\"status\",\"operator\":\"EQ\",\"value\":\"customer\"},{\"field\":\"contact.attr.plan\",\"operator\":\"EQ\",\"value\":\"gold\"},{\"field\":\"email\",\"operator\":\"IS_NOT_NULL\",\"value\":null}]"
},
)
res.raise_for_status()
data = res.json()
{
"id": 12,
"name": "Gold customers with email",
"description": "Customers on the Gold plan we can email",
"expressionsJson": "[{\"field\":\"status\",\"operator\":\"EQ\",\"value\":\"customer\"},{\"field\":\"contact.attr.plan\",\"operator\":\"EQ\",\"value\":\"gold\"},{\"field\":\"email\",\"operator\":\"IS_NOT_NULL\",\"value\":null}]",
"matchCount": 342,
"matchCountUpdatedAt": "2026-11-07T02:00:00Z"
}
Update a segment
Replaces the segment’s name, description and rules. Send all three: an omitted field is cleared.
contacts:writePath parameters
segmentIdintegerrequiredThe segment’sid.
Request body
namestringrequiredSegment name.descriptionstringnullableOptional description. Replaced on update: omit it and it is cleared.expressionsJsonstringrequiredThe rules as a serialised JSON array. See Rules at the top of this page.
Returns
200The segment object.
Errors
- 400
VALIDATION_FAILED`name` or `expressionsJson` is blank, or `description` is longer than 2000 characters. - 400
INVALID_REQUESTThe rules use a field or operator that is not supported. Bad rules are rejected when you save, because the count runs at save. - 404
SEGMENT_NOT_FOUNDNo segment with this ID in your organisation.
curl -X PUT "https://api.cx.na6iq.com/api/v1/segments/42" \
-H "Authorization: Bearer $NATIQ_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"name": "Gold customers with email",
"description": "Customers on the Gold plan we can email",
"expressionsJson": "[{\"field\":\"contact.attr.plan\",\"operator\":\"EQ\",\"value\":\"gold\"},{\"field\":\"email\",\"operator\":\"IS_NOT_NULL\",\"value\":null}]"
}'
const res = await fetch('https://api.cx.na6iq.com/api/v1/segments/42', {
method: 'PUT',
headers: {
Authorization: `Bearer ${process.env.NATIQ_TOKEN}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({
"name": "Gold customers with email",
"description": "Customers on the Gold plan we can email",
"expressionsJson": "[{\"field\":\"contact.attr.plan\",\"operator\":\"EQ\",\"value\":\"gold\"},{\"field\":\"email\",\"operator\":\"IS_NOT_NULL\",\"value\":null}]"
}),
})
if (!res.ok) throw new Error((await res.json().catch(() => ({}))).error?.message ?? `HTTP ${res.status}`)
const data = await res.json()
import os, requests
res = requests.put(
"https://api.cx.na6iq.com/api/v1/segments/42",
headers={"Authorization": f"Bearer {os.environ['NATIQ_TOKEN']}"},
json={
"name": "Gold customers with email",
"description": "Customers on the Gold plan we can email",
"expressionsJson": "[{\"field\":\"contact.attr.plan\",\"operator\":\"EQ\",\"value\":\"gold\"},{\"field\":\"email\",\"operator\":\"IS_NOT_NULL\",\"value\":null}]"
},
)
res.raise_for_status()
data = res.json()
{
"id": 12,
"name": "Gold customers with email",
"description": "Customers on the Gold plan we can email",
"expressionsJson": "[{\"field\":\"status\",\"operator\":\"EQ\",\"value\":\"customer\"},{\"field\":\"contact.attr.plan\",\"operator\":\"EQ\",\"value\":\"gold\"},{\"field\":\"email\",\"operator\":\"IS_NOT_NULL\",\"value\":null}]",
"matchCount": 342,
"matchCountUpdatedAt": "2026-11-07T02:00:00Z"
}
Delete a segment
Deletes the segment. The contacts it matched are not affected.
contacts:writePath parameters
segmentIdintegerrequiredThe segment’sid.
Returns
204The segment is deleted.
Errors
- 404
SEGMENT_NOT_FOUNDNo segment with this ID in your organisation.
curl -X DELETE "https://api.cx.na6iq.com/api/v1/segments/42" \
-H "Authorization: Bearer $NATIQ_TOKEN"
const res = await fetch('https://api.cx.na6iq.com/api/v1/segments/42', {
method: 'DELETE',
headers: {
Authorization: `Bearer ${process.env.NATIQ_TOKEN}`,
},
})
if (!res.ok) throw new Error((await res.json().catch(() => ({}))).error?.message ?? `HTTP ${res.status}`)
import os, requests
res = requests.delete(
"https://api.cx.na6iq.com/api/v1/segments/42",
headers={"Authorization": f"Bearer {os.environ['NATIQ_TOKEN']}"},
)
res.raise_for_status()
Preview a segment’s contacts
Returns a page of the contacts that match the segment right now, as short summaries. Unlike matchCount this is computed live.
contacts:read Offset paginatedPath parameters
segmentIdintegerrequiredThe segment’sid.
Query parameters
pageintegerZero-based page number. Default0.sizeintegerPage size. Default20; keep it at 100 or below.
Returns
200A page of results.
Errors
- 400
INVALID_REQUESTThe rules use a field or operator that is not supported. Bad rules are rejected when you save, because the count runs at save. - 404
SEGMENT_NOT_FOUNDNo segment with this ID in your organisation.
curl -X GET "https://api.cx.na6iq.com/api/v1/segments/42/preview?page=0&size=25" \
-H "Authorization: Bearer $NATIQ_TOKEN"
const res = await fetch('https://api.cx.na6iq.com/api/v1/segments/42/preview?page=0&size=25', {
method: 'GET',
headers: {
Authorization: `Bearer ${process.env.NATIQ_TOKEN}`,
},
})
if (!res.ok) throw new Error((await res.json().catch(() => ({}))).error?.message ?? `HTTP ${res.status}`)
const data = await res.json()
import os, requests
res = requests.get(
"https://api.cx.na6iq.com/api/v1/segments/42/preview?page=0&size=25",
headers={"Authorization": f"Bearer {os.environ['NATIQ_TOKEN']}"},
)
res.raise_for_status()
data = res.json()
{
"data": [
{
"id": 1842,
"displayName": "Layla Haddad",
"email": "layla@example.com",
"phone": "+962791234567",
"status": "customer"
}
],
"page": 0,
"size": 20,
"totalElements": 342,
"totalPages": 18
}