Skip to main content

UC-023 — Advanced Contact Segmentation

FieldValue
IDUC-023
GoalSegment contacts with advanced filters to create targeted lists
ChannelAll
Complexity⭐⭐⭐ Advanced
Estimated time30 minutes
APIs involvedGET /api/partner-gateway/v1/contacts, POST /contacts, PUT /contacts/{id}, DELETE /contacts/{id}, POST /contacts/list/contacts

Real-world scenarios

  • TurismoVeneto — Segment by region: Filter 20,000 contacts by region of residence and create separate lists for Lombardy, Veneto and Emilia-Romagna for geo-targeted promotions.
  • LuxuryStore — VIP list: Identify customers with total spending above 5,000 EUR and create a VIP list for exclusive previews and private event invitations.
  • FreshMarket — Filter by last purchase: Select customers who haven't purchased in over 90 days for a re-engagement campaign with discount coupons.

Segmentation flow

The diagram shows the flow: from the full list, multiple filters (region, attributes, date) are applied to create segmented lists ready for campaigns.

Prerequisites

  • Active API Key with contact management permissions
  • Contacts imported into the platform (see UC-007)
  • At least one existing contact list with populated custom fields

Step 1 — Retrieve contacts with filters

Query contacts applying region filters.

curl -X GET "https://lora-api.agiletelecom.com/api/partner-gateway/v1/contacts?region=Lombardia&limit=50&offset=0" \
-H "X-Api-Key: YOUR_API_KEY"

Response — Filtered contacts

{
"contacts": [
{
"id": "cnt-001",
"firstName": "Marco",
"lastName": "Rossi",
"phoneNumber": "+393471234567",
"email": "marco.rossi@email.it",
"region": "Lombardia",
"customFields": {
"lastPurchaseDate": "2026-03-15",
"totalSpent": 1250.00,
"preferredChannel": "WHATSAPP"
}
},
{
"id": "cnt-002",
"firstName": "Laura",
"lastName": "Bianchi",
"phoneNumber": "+393489876543",
"email": "laura.bianchi@email.it",
"region": "Lombardia",
"customFields": {
"lastPurchaseDate": "2026-01-10",
"totalSpent": 6800.00,
"preferredChannel": "SMS"
}
}
],
"total": 4350,
"limit": 50,
"offset": 0
}
Behind the scenes — Available filters and query logic
  1. Standard filters: region, city, firstName, lastName, email, phoneNumber can be filtered directly as query parameters.
  2. Custom fields: Fields in customFields can be filtered using the syntax customFields.fieldname=value.
  3. Pagination: Use limit and offset to paginate large result sets. The maximum for limit is 100.
  4. Sorting: Use sort=field&order=asc|desc to sort results (e.g., sort=customFields.totalSpent&order=desc).
  5. Combining filters: All filters use logical AND. For complex OR logic, execute multiple queries and combine results client-side.

Step 2 — Create a segmented list

Create a new list for the identified segment.

curl -X POST https://lora-api.agiletelecom.com/api/partner-gateway/v1/contacts/list \
-H "Content-Type: application/json" \
-H "X-Api-Key: YOUR_API_KEY" \
-d '{
"name": "VIP Lombardia - Spesa > 5000 EUR",
"description": "Clienti lombardi con spesa totale superiore a 5000 EUR"
}'

Response — List created

{
"id": "list-vip-lombardia-001",
"name": "VIP Lombardia - Spesa > 5000 EUR",
"description": "Clienti lombardi con spesa totale superiore a 5000 EUR",
"contactCount": 0,
"createdAt": "2026-04-09T11:00:00+02:00"
}

Step 3 — Add contacts to the segmented list

Add the filtered contacts to the new list using their IDs.

curl -X POST https://lora-api.agiletelecom.com/api/partner-gateway/v1/contacts/list/contacts \
-H "Content-Type: application/json" \
-H "X-Api-Key: YOUR_API_KEY" \
-d '{
"listId": "list-vip-lombardia-001",
"contactIds": ["cnt-002", "cnt-015", "cnt-089", "cnt-142", "cnt-278"]
}'

Response — Contacts added

{
"listId": "list-vip-lombardia-001",
"addedContacts": 5,
"duplicateContacts": 0,
"invalidContacts": 0,
"totalContactsInList": 5
}

:::tip Automating segmentation For large lists, automate the process server-side: retrieve all filtered contacts with pagination, collect the IDs and send them in batches to the list. The batch limit is 1,000 contacts. :::

Expected result

StepActionResult
1GET /contacts?region=LombardiaFiltered list of Lombardy contacts
2POST /contacts/listNew segmented list created
3POST /contacts/list/contactsVIP contacts added to the list

Complete end-to-end example

# 1. Retrieve VIP Lombardy contacts (with pagination)
CONTACTS=$(curl -s -X GET \
"https://lora-api.agiletelecom.com/api/partner-gateway/v1/contacts?region=Lombardia&limit=100&offset=0" \
-H "X-Api-Key: YOUR_API_KEY")

# 2. Filter client-side for spending > 5000 EUR
VIP_IDS=$(echo "$CONTACTS" | jq -r '[.contacts[] | select(.customFields.totalSpent > 5000) | .id] | join(",")')
echo "VIP IDs: $VIP_IDS"

# 3. Create the segmented list
LIST_ID=$(curl -s -X POST https://lora-api.agiletelecom.com/api/partner-gateway/v1/contacts/list \
-H "Content-Type: application/json" \
-H "X-Api-Key: YOUR_API_KEY" \
-d '{
"name": "VIP Lombardia - Spesa > 5000 EUR",
"description": "Segmento VIP per campagna esclusiva"
}' | jq -r '.id')

echo "List ID: $LIST_ID"

# 4. Add contacts to the list
IDS_JSON=$(echo "$CONTACTS" | jq '[.contacts[] | select(.customFields.totalSpent > 5000) | .id]')

curl -s -X POST https://lora-api.agiletelecom.com/api/partner-gateway/v1/contacts/list/contacts \
-H "Content-Type: application/json" \
-H "X-Api-Key: YOUR_API_KEY" \
-d "{
\"listId\": \"${LIST_ID}\",
\"contactIds\": ${IDS_JSON}
}" | jq .

Variants

Segmentation by inactivity (re-engagement)

Filter contacts who haven't purchased in over 90 days:

curl -X GET "https://lora-api.agiletelecom.com/api/partner-gateway/v1/contacts?customFields.lastPurchaseDate.before=2026-01-09&limit=100" \
-H "X-Api-Key: YOUR_API_KEY"

Remove a contact from a list

If a contact should no longer belong to a segment:

curl -X DELETE "https://lora-api.agiletelecom.com/api/partner-gateway/v1/contacts/list/contacts?listId=list-vip-lombardia-001&contactId=cnt-278" \
-H "X-Api-Key: YOUR_API_KEY"

Common errors

400 Bad Request — Invalid filter

{
"status": "fail",
"data": {
"filter": "Unknown filter field: invalidField"
}
}

Solution: Verify the filterable field names. For custom fields use the syntax customFields.fieldName.

404 Not Found — Contact not found

{
"status": "fail",
"data": {
"contactId": "Contact not found: cnt-999"
}
}

Solution: The contact ID may have been deleted or may not exist. Verify the ID with a GET before adding to the list.

401 Unauthorized — Missing or invalid API Key

{
"status": "fail",
"data": {
"authentication": "Invalid or missing API key"
}
}

Solution: Verify that the X-Api-Key header is present and that the key is active in the platform dashboard.

Next steps

References