Skip to main content

Marketing Lists & Audiences API

Overview

The Marketing Lists & Audiences API provides comprehensive management of customer segmentation within the Stack9 Digital Experience Platform. This API enables you to create dynamic audiences based on behavior and attributes, manage static lists for targeted campaigns, and orchestrate sophisticated segmentation strategies for personalized marketing at scale.

Resource Description

Marketing Audiences

Marketing audiences represent dynamic segments that automatically update based on defined criteria. Key characteristics:

  • Dynamic Membership: Subscribers automatically join or leave based on real-time attribute changes
  • Rule-Based Segmentation: Define complex criteria using subscriber attributes, behaviors, and engagement patterns
  • Real-Time Updates: Audience membership recalculates as subscriber data changes
  • Scalable Performance: Optimized for millions of subscribers with sub-second query performance
  • Cross-Channel Activation: Use audiences across email, SMS, push, and other channels

Marketing Lists

Marketing lists represent static groups of subscribers for specific campaigns or purposes. Key characteristics:

  • Static Membership: Manually controlled subscriber additions and removals
  • Import/Export Support: Bulk operations for list management via CSV/Excel
  • Campaign Association: Direct linkage to marketing campaigns and emails
  • Suppression Lists: Support for exclusion lists and compliance requirements
  • Version Control: Track list changes over time with audit trails

List-Audience Relationships

Lists can be associated with audiences to create hybrid segmentation strategies:

  • Dynamic Lists: Lists that inherit members from audiences
  • List Unions: Combine multiple lists and audiences
  • Exclusion Rules: Remove audience members who appear in suppression lists
  • Priority Management: Control precedence when subscribers belong to multiple segments

Key Features

  • Flexible Segmentation: Combine static and dynamic approaches for optimal targeting
  • Bulk Operations: Import thousands of subscribers with job tracking
  • Real-Time Sync: Immediate updates across all marketing channels
  • Performance Analytics: Track segment growth and engagement metrics
  • Compliance Support: Built-in GDPR/CCPA compliance with audit trails
  • API-First Design: Full programmatic control for automation workflows
  • Job Management: Asynchronous processing for large-scale operations

Authentication

All endpoints require API key authentication:

X-API-Key: your-api-key-here

Marketing Audiences

Create Audience

Create a new dynamic audience for automated segmentation.

POST /api/audiences

Parameters

ParameterTypeRequiredDescription
namestringYesUnique, descriptive name for the audience

Example Request

curl -X POST \
https://apis.app.stack9.co/api/audiences \
-H 'X-API-Key: your-api-key-here' \
-H 'Content-Type: application/json' \
-d '{
"name": "High-Value Customers"
}'

Example Response

{
"id": "aud_Kj9mNp2QrT8xLw3"
}

Error Responses

400 Bad Request
{
"message": "Invalid audience data",
"code": "INVALID_AUDIENCE",
"issues": [
{
"field": "name",
"message": "Audience name already exists"
}
]
}

List Audiences

Retrieve all audiences with filtering and pagination support.

POST /api/audiences/list

Parameters

ParameterTypeRequiredDescription
pagenumberYesPage number (1-based)
limitnumberYesItems per page (max: 100)
searchstringNoSearch audiences by name
filtersobjectNoFilter criteria object
filters.nameobjectNoFilter by audience name
filters.idobjectNoFilter by audience ID
filters.created_atobjectNoFilter by creation date
filters.updated_atobjectNoFilter by last update date

Filter Operations

Each filter field supports the following operations:

  • eq: Equals
  • ne: Not equals
  • like: Contains (case-insensitive)
  • in: In array of values
  • between: Between two values (for dates)
  • gt, gte, lt, lte: Comparison operators

Example Request

curl -X POST \
https://apis.app.stack9.co/api/audiences/list \
-H 'X-API-Key: your-api-key-here' \
-H 'Content-Type: application/json' \
-d '{
"page": 1,
"limit": 20,
"search": "customers",
"filters": {
"created_at": {
"operation": "between",
"value": ["2024-01-01T00:00:00Z", "2024-12-31T23:59:59Z"]
}
}
}'

Example Response

{
"results": [
{
"id": "aud_Kj9mNp2QrT8xLw3",
"name": "High-Value Customers",
"created_at": "2024-03-15T10:30:00.000Z",
"updated_at": "2024-03-20T14:45:00.000Z",
"version": 3
},
{
"id": "aud_Nm7kPq4RsU9yMx5",
"name": "Newsletter Subscribers",
"created_at": "2024-02-01T08:00:00.000Z",
"updated_at": null,
"version": 1
}
],
"total": 15,
"totalPages": 1
}

Get Audience by ID

Retrieve detailed information about a specific audience.

GET /api/audiences/{audience_id}

Parameters

ParameterTypeRequiredDescription
audience_idstringYesThe audience's unique identifier

Example Request

curl -X GET \
https://apis.app.stack9.co/api/audiences/aud_Kj9mNp2QrT8xLw3 \
-H 'X-API-Key: your-api-key-here'

Example Response

{
"id": "aud_Kj9mNp2QrT8xLw3",
"name": "High-Value Customers",
"created_at": "2024-03-15T10:30:00.000Z",
"updated_at": "2024-03-20T14:45:00.000Z",
"version": 3
}

Update Audience

Update an existing audience's properties.

PUT /api/audiences/{id}

Parameters

ParameterTypeRequiredDescription
idstringYesThe audience's unique identifier
namestringYesNew name for the audience

Example Request

curl -X PUT \
https://apis.app.stack9.co/api/audiences/aud_Kj9mNp2QrT8xLw3 \
-H 'X-API-Key: your-api-key-here' \
-H 'Content-Type: application/json' \
-d '{
"name": "VIP High-Value Customers"
}'

Example Response

{
"id": "aud_Kj9mNp2QrT8xLw3"
}

Delete Audience

Permanently delete an audience and remove all subscriber associations.

DELETE /api/audiences/{audience_id}

Parameters

ParameterTypeRequiredDescription
audience_idstringYesThe audience's unique identifier

Example Request

curl -X DELETE \
https://apis.app.stack9.co/api/audiences/aud_Kj9mNp2QrT8xLw3 \
-H 'X-API-Key: your-api-key-here'

Example Response

{
"id": "aud_Kj9mNp2QrT8xLw3"
}

Add Subscriber to Audience

Add a subscriber to an audience for dynamic segmentation.

POST /api/audiences/{audience_id}/subscribers

Parameters

ParameterTypeRequiredDescription
audience_idstringYesThe audience's unique identifier
subscriber_idstringYesThe subscriber's unique identifier

Example Request

curl -X POST \
https://apis.app.stack9.co/api/audiences/aud_Kj9mNp2QrT8xLw3/subscribers \
-H 'X-API-Key: your-api-key-here' \
-H 'Content-Type: application/json' \
-d '{
"subscriber_id": "sub_Pq9nRt5YsW2zNx8"
}'

Example Response

{
"audience_id": "aud_Kj9mNp2QrT8xLw3",
"subscriber_id": "sub_Pq9nRt5YsW2zNx8"
}

Remove Subscriber from Audience

Remove a subscriber from an audience.

DELETE /api/audiences/{audience_id}/subscribers/{subscriber_id}

Parameters

ParameterTypeRequiredDescription
audience_idstringYesThe audience's unique identifier
subscriber_idstringYesThe subscriber's unique identifier

Example Request

curl -X DELETE \
https://apis.app.stack9.co/api/audiences/aud_Kj9mNp2QrT8xLw3/subscribers/sub_Pq9nRt5YsW2zNx8 \
-H 'X-API-Key: your-api-key-here'

Example Response

{
"audience_id": "aud_Kj9mNp2QrT8xLw3",
"subscriber_id": "sub_Pq9nRt5YsW2zNx8"
}

Marketing Lists

Create List

Create a new marketing list with optional audience association.

POST /api/lists

Parameters

ParameterTypeRequiredDescription
namestringYesMemorable name for the list
modestringYesList mode: static or dynamic
audience_idstringYesAssociated audience ID (use default if none)
jobsarrayNoImport jobs to process after creation

Example Request - Static List

curl -X POST \
https://apis.app.stack9.co/api/lists \
-H 'X-API-Key: your-api-key-here' \
-H 'Content-Type: application/json' \
-d '{
"name": "Q1 2024 Campaign Targets",
"mode": "static",
"audience_id": "aud_default"
}'

Example Request - Dynamic List with Audience

curl -X POST \
https://apis.app.stack9.co/api/lists \
-H 'X-API-Key: your-api-key-here' \
-H 'Content-Type: application/json' \
-d '{
"name": "Auto-Updated VIP List",
"mode": "dynamic",
"audience_id": "aud_Kj9mNp2QrT8xLw3"
}'

Example Response

{
"id": "list_Rt7mKp3QsU9xNw4"
}

List All Lists

Retrieve all marketing lists with comprehensive filtering.

POST /api/lists/list

Parameters

ParameterTypeRequiredDescription
pagenumberYesPage number (1-based)
limitnumberYesItems per page (max: 100)
searchstringNoSearch lists by name
filtersobjectNoFilter criteria object
filters.idobjectNoFilter by list ID
filters.nameobjectNoFilter by list name
filters.modeobjectNoFilter by mode (static/dynamic)
filters.audience_idobjectNoFilter by associated audience
filters.created_atobjectNoFilter by creation date
filters.updated_atobjectNoFilter by last update date

Example Request

curl -X POST \
https://apis.app.stack9.co/api/lists/list \
-H 'X-API-Key: your-api-key-here' \
-H 'Content-Type: application/json' \
-d '{
"page": 1,
"limit": 25,
"filters": {
"mode": {
"operation": "eq",
"value": "static"
}
}
}'

Example Response

{
"results": [
{
"id": "list_Rt7mKp3QsU9xNw4",
"name": "Q1 2024 Campaign Targets",
"mode": "static",
"audience_id": "aud_default",
"audience_name": "All Subscribers",
"created_at": "2024-01-15T09:00:00.000Z",
"updated_at": "2024-03-10T16:30:00.000Z",
"version": 5
},
{
"id": "list_Nm8pQr5TsW3yOx6",
"name": "Product Launch Early Access",
"mode": "static",
"audience_id": "aud_Kj9mNp2QrT8xLw3",
"audience_name": "High-Value Customers",
"created_at": "2024-02-20T11:15:00.000Z",
"updated_at": null,
"version": 1
}
],
"total": 42,
"totalPages": 2
}

Get List by ID

Retrieve detailed information about a specific list including job history.

GET /api/lists/{list_id}

Parameters

ParameterTypeRequiredDescription
list_idstringYesThe list's unique identifier

Example Request

curl -X GET \
https://apis.app.stack9.co/api/lists/list_Rt7mKp3QsU9xNw4 \
-H 'X-API-Key: your-api-key-here'

Example Response

{
"id": "list_Rt7mKp3QsU9xNw4",
"name": "Q1 2024 Campaign Targets",
"mode": "static",
"audience_id": "aud_default",
"created_at": "2024-01-15T09:00:00.000Z",
"updated_at": "2024-03-10T16:30:00.000Z",
"version": 5,
"jobs": [
{
"id": "job_Wp5nTq8RvY3zMx9",
"list_id": "list_Rt7mKp3QsU9xNw4",
"status": "completed",
"import_file": {
"file_url": "https://storage.stack9.io/imports/2024/03/subscribers.csv",
"import_type": "create_update",
"audience_id": "aud_default"
},
"processed_rows": 5000,
"total_rows": 5000,
"created_contacts": 3500,
"updated_contacts": 1500,
"removed_contacts": 0,
"invalid_contacts": 0,
"error_details_url": null,
"created_date": "2024-03-10T16:30:00.000Z"
}
]
}

Update List

Update list properties and manage import jobs.

PUT /api/lists/{id}

Parameters

ParameterTypeRequiredDescription
idstringYesThe list's unique identifier
namestringYesNew name for the list
jobsarrayNoImport jobs to add or update

Example Request

curl -X PUT \
https://apis.app.stack9.co/api/lists/list_Rt7mKp3QsU9xNw4 \
-H 'X-API-Key: your-api-key-here' \
-H 'Content-Type: application/json' \
-d '{
"name": "Q2 2024 Campaign Targets - Updated"
}'

Example Response

{
"id": "list_Rt7mKp3QsU9xNw4"
}

Delete List

Permanently delete a list and all associated data.

DELETE /api/lists/{list_id}

Parameters

ParameterTypeRequiredDescription
list_idstringYesThe list's unique identifier

Example Request

curl -X DELETE \
https://apis.app.stack9.co/api/lists/list_Rt7mKp3QsU9xNw4 \
-H 'X-API-Key: your-api-key-here'

Example Response

{
"id": "list_Rt7mKp3QsU9xNw4"
}

Subscriber Management within Lists

Add Subscriber to List

Manually add a single subscriber to a static list.

POST /api/lists/{list_id}/subscribers

Parameters

ParameterTypeRequiredDescription
list_idstringYesThe list's unique identifier
subscriber_idstringYesThe subscriber's unique identifier

Example Request

curl -X POST \
https://apis.app.stack9.co/api/lists/list_Rt7mKp3QsU9xNw4/subscribers \
-H 'X-API-Key: your-api-key-here' \
-H 'Content-Type: application/json' \
-d '{
"subscriber_id": "sub_Yp8nWq5TvX4zKm2"
}'

Example Response

{
"list_id": "list_Rt7mKp3QsU9xNw4",
"subscriber_id": "sub_Yp8nWq5TvX4zKm2"
}

Remove Subscriber from List

Remove a subscriber from a list.

DELETE /api/lists/{list_id}/subscribers/{subscriber_id}

Parameters

ParameterTypeRequiredDescription
list_idstringYesThe list's unique identifier
subscriber_idstringYesThe subscriber's unique identifier

Example Request

curl -X DELETE \
https://apis.app.stack9.co/api/lists/list_Rt7mKp3QsU9xNw4/subscribers/sub_Yp8nWq5TvX4zKm2 \
-H 'X-API-Key: your-api-key-here'

Example Response

{
"list_id": "list_Rt7mKp3QsU9xNw4",
"subscriber_id": "sub_Yp8nWq5TvX4zKm2"
}

Bulk Import Operations

Import Subscribers to List

Initiate a bulk import job to add, update, or remove subscribers from a list.

POST /api/lists/{list_id}/import

Parameters

ParameterTypeRequiredDescription
list_idstringYesThe list's unique identifier
file_urlstringYesURL of the uploaded CSV/Excel file
import_typestringYesImport operation type
columns_mappingobjectNoMap CSV columns to subscriber fields

Import Types

  • create_only: Only create new subscribers, skip existing
  • update_only: Only update existing subscribers, skip new
  • create_update: Create new and update existing subscribers
  • remove_only: Remove subscribers from the list

Column Mapping

Map CSV column headers to subscriber fields:

{
"columns_mapping": {
"First Name": "first_name",
"Last Name": "last_name",
"Email Address": "email",
"Company": "company",
"Customer ID": "customer_id",
"Signup Date": "created_at"
}
}

Example Request - Create/Update Import

curl -X POST \
https://apis.app.stack9.co/api/lists/list_Rt7mKp3QsU9xNw4/import \
-H 'X-API-Key: your-api-key-here' \
-H 'Content-Type: application/json' \
-d '{
"file_url": "https://storage.stack9.io/uploads/2024/03/subscribers_batch.csv",
"import_type": "create_update",
"columns_mapping": {
"Email": "email",
"FirstName": "first_name",
"LastName": "last_name",
"Company": "additional_fields_data.company",
"CustomerType": "additional_fields_data.customer_type"
}
}'

Example Response

{
"id": "job_Zq9pRt6UwY5aNx3",
"list_id": "list_Rt7mKp3QsU9xNw4",
"status": "pending",
"import_file": {
"file_url": "https://storage.stack9.io/uploads/2024/03/subscribers_batch.csv",
"import_type": "create_update",
"audience_id": "aud_default"
},
"processed_rows": 0,
"total_rows": 10000,
"created_contacts": 0,
"updated_contacts": 0,
"invalid_contacts": 0,
"error_details_url": null,
"created_date": "2024-03-15T14:00:00.000Z"
}

Get Import Jobs

Retrieve all import jobs for a specific list.

GET /api/lists/{list_id}/jobs

Parameters

ParameterTypeRequiredDescription
list_idstringYesThe list's unique identifier
pagenumberNoPage number (default: 1)
limitnumberNoItems per page (default: 20, max: 100)

Example Request

curl -X GET \
'https://apis.app.stack9.co/api/lists/list_Rt7mKp3QsU9xNw4/jobs?page=1&limit=10' \
-H 'X-API-Key: your-api-key-here'

Example Response

{
"results": [
{
"id": "job_Zq9pRt6UwY5aNx3",
"list_id": "list_Rt7mKp3QsU9xNw4",
"status": "completed",
"import_file": {
"file_url": "https://storage.stack9.io/uploads/2024/03/subscribers_batch.csv",
"import_type": "create_update",
"audience_id": "aud_default"
},
"processed_rows": 10000,
"total_rows": 10000,
"created_contacts": 7500,
"updated_contacts": 2500,
"removed_contacts": 0,
"invalid_contacts": 25,
"error_details_url": "https://storage.stack9.io/errors/job_Zq9pRt6UwY5aNx3.csv",
"created_date": "2024-03-15T14:00:00.000Z"
},
{
"id": "job_Wp5nTq8RvY3zMx9",
"list_id": "list_Rt7mKp3QsU9xNw4",
"status": "processing",
"import_file": {
"file_url": "https://storage.stack9.io/uploads/2024/03/weekly_update.csv",
"import_type": "update_only",
"audience_id": "aud_default"
},
"processed_rows": 2500,
"total_rows": 5000,
"created_contacts": 0,
"updated_contacts": 2450,
"removed_contacts": 0,
"invalid_contacts": 50,
"error_details_url": null,
"created_date": "2024-03-16T10:00:00.000Z"
}
],
"total": 15,
"totalPages": 2
}

Download Import Job Errors

Download a detailed error report for a failed or partially successful import job.

GET /api/lists/{list_id}/jobs/{job_id}/errors/download

Parameters

ParameterTypeRequiredDescription
list_idstringYesThe list's unique identifier
job_idstringYesThe job's unique identifier

Example Request

curl -X GET \
https://apis.app.stack9.co/api/lists/list_Rt7mKp3QsU9xNw4/jobs/job_Zq9pRt6UwY5aNx3/errors/download \
-H 'X-API-Key: your-api-key-here'

Example Response

{
"file_url": "https://storage.stack9.io/downloads/errors/job_Zq9pRt6UwY5aNx3_errors_20240315_140530.csv?token=eyJhbGciOiJIUzI1NiIs..."
}

The downloaded CSV file contains:

  • Row number from original file
  • Email address
  • Error type and message
  • Validation details
  • Suggested fixes

Advanced Segmentation Strategies

Dynamic Audience with Behavioral Rules

Create sophisticated audiences that automatically update based on subscriber behavior:

# Step 1: Create the audience
curl -X POST \
https://apis.app.stack9.co/api/audiences \
-H 'X-API-Key: your-api-key-here' \
-H 'Content-Type: application/json' \
-d '{
"name": "Engaged Premium Customers"
}'

# Step 2: Define audience rules (via UI or separate API)
# Rules example:
# - Customer type = "premium"
# - Email opens in last 30 days > 5
# - Total purchases > $1000
# - Not in suppression list

# Step 3: Create dynamic list linked to audience
curl -X POST \
https://apis.app.stack9.co/api/lists \
-H 'X-API-Key: your-api-key-here' \
-H 'Content-Type: application/json' \
-d '{
"name": "Active Premium Segment",
"mode": "dynamic",
"audience_id": "aud_Kj9mNp2QrT8xLw3"
}'

Hybrid Segmentation

Combine static lists with dynamic audiences for complex targeting:

# Step 1: Create base audience
curl -X POST \
https://apis.app.stack9.co/api/audiences \
-H 'X-API-Key: your-api-key-here' \
-H 'Content-Type: application/json' \
-d '{
"name": "Geographic Target - West Coast"
}'

# Step 2: Create static list for VIP overrides
curl -X POST \
https://apis.app.stack9.co/api/lists \
-H 'X-API-Key: your-api-key-here' \
-H 'Content-Type: application/json' \
-d '{
"name": "VIP Override List",
"mode": "static",
"audience_id": "aud_geographic_west"
}'

# Step 3: Import VIP subscribers
curl -X POST \
https://apis.app.stack9.co/api/lists/list_vip_override/import \
-H 'X-API-Key: your-api-key-here' \
-H 'Content-Type: application/json' \
-d '{
"file_url": "https://storage.stack9.io/vip_list.csv",
"import_type": "create_only"
}'

A/B Test Segments

Create multiple segments for campaign testing:

# Create test segments
segments=("Control Group" "Test A - Subject Line" "Test B - Content" "Test C - Send Time")

for segment in "${segments[@]}"; do
curl -X POST \
https://apis.app.stack9.co/api/lists \
-H 'X-API-Key: your-api-key-here' \
-H 'Content-Type: application/json' \
-d '{
"name": "'"$segment"'",
"mode": "static",
"audience_id": "aud_campaign_base"
}'
done

# Import randomized segments
curl -X POST \
https://apis.app.stack9.co/api/lists/list_control/import \
-H 'X-API-Key: your-api-key-here' \
-H 'Content-Type: application/json' \
-d '{
"file_url": "https://storage.stack9.io/ab_test_segments.csv",
"import_type": "create_only"
}'

Job Processing & Monitoring

Job Status Values

  • pending: Job queued for processing
  • processing: Actively importing/processing records
  • completed: Successfully finished all operations
  • cancelled: Job cancelled by user or system

Monitor Import Job Progress

Poll job status for real-time progress updates:

#!/bin/bash
JOB_ID="job_Zq9pRt6UwY5aNx3"
LIST_ID="list_Rt7mKp3QsU9xNw4"

while true; do
response=$(curl -s -X GET \
"https://apis.app.stack9.co/api/lists/$LIST_ID/jobs?limit=1" \
-H 'X-API-Key: your-api-key-here')

status=$(echo $response | jq -r ".results[0].status")
processed=$(echo $response | jq -r ".results[0].processed_rows")
total=$(echo $response | jq -r ".results[0].total_rows")

echo "Status: $status | Progress: $processed/$total"

if [ "$status" = "completed" ] || [ "$status" = "cancelled" ]; then
break
fi

sleep 5
done

# Get final results
echo "Import completed!"
echo "Created: $(echo $response | jq -r '.results[0].created_contacts')"
echo "Updated: $(echo $response | jq -r '.results[0].updated_contacts')"
echo "Errors: $(echo $response | jq -r '.results[0].invalid_contacts')"

Best Practices

Segmentation Strategy

  1. Audience Hierarchy: Create broad audiences and use lists for specific campaigns
  2. Naming Conventions: Use descriptive, consistent naming patterns
  3. Regular Cleanup: Archive or delete unused segments quarterly
  4. Performance Testing: Test segment queries with small samples first
  5. Documentation: Document segment criteria and business logic

Import Operations

  1. File Preparation:

    • Validate email formats before import
    • Remove duplicates within the file
    • Use UTF-8 encoding for international characters
    • Limit files to 1 million rows per import
  2. Column Mapping:

    • Map all required fields explicitly
    • Use dot notation for nested custom fields
    • Validate date formats match ISO 8601
  3. Error Handling:

    • Always download and review error reports
    • Implement retry logic for temporary failures
    • Keep original files for audit purposes

Performance Optimization

  1. Batch Operations:

    • Use bulk import instead of individual API calls
    • Process large lists during off-peak hours
    • Implement pagination for large result sets
  2. Caching Strategy:

    • Cache audience/list metadata locally
    • Refresh cache on webhook events
    • Use ETags for conditional requests
  3. Query Optimization:

    • Use specific filters instead of post-processing
    • Limit result fields to required data only
    • Implement cursor-based pagination for large datasets

Compliance & Privacy

  1. Data Governance:

    • Implement retention policies for inactive subscribers
    • Track consent status in custom fields
    • Maintain suppression lists for opt-outs
  2. Audit Trail:

    • Log all list modifications
    • Track import job history
    • Document segment criteria changes
  3. Access Control:

    • Use separate API keys for different operations
    • Implement IP whitelisting for production
    • Rotate API keys regularly

Integration Patterns

Campaign Orchestration

Integrate lists and audiences with campaign workflows:

// Example: Node.js campaign targeting
async function launchTargetedCampaign() {
// Step 1: Create audience
const audience = await createAudience({
name: "Product Launch Targets"
});

// Step 2: Create campaign list
const list = await createList({
name: "Launch Campaign List",
mode: "dynamic",
audience_id: audience.id
});

// Step 3: Import additional targets
const importJob = await importSubscribers(list.id, {
file_url: "https://storage.stack9.io/launch_targets.csv",
import_type: "create_update"
});

// Step 4: Wait for import completion
await waitForJobCompletion(importJob.id);

// Step 5: Create and send campaign
const campaign = await createCampaign({
name: "Product Launch 2024",
list_id: list.id,
template_id: "tmpl_launch_announce"
});

return campaign;
}

Real-Time Personalization

Use audiences for dynamic content personalization:

# Example: Python personalization engine
import requests
from typing import List, Dict

class PersonalizationEngine:
def __init__(self, api_key: str):
self.api_key = api_key
self.base_url = "https://apis.app.stack9.co/api"

def get_subscriber_segments(self, email: str) -> List[str]:
"""Get all segments for a subscriber"""
# Get subscriber details
subscriber = self.get_subscriber_by_email(email)

segments = []
segments.extend(subscriber.get('audiences', []))
segments.extend(subscriber.get('lists', []))

return segments

def get_personalized_content(self, email: str) -> Dict:
"""Generate personalized content based on segments"""
segments = self.get_subscriber_segments(email)

content = {
'hero_image': self.select_hero_image(segments),
'product_recommendations': self.get_recommendations(segments),
'exclusive_offers': self.get_offers(segments),
'content_blocks': self.select_content_blocks(segments)
}

return content

def select_hero_image(self, segments: List[str]) -> str:
"""Select hero image based on segment priority"""
if 'aud_vip_customers' in segments:
return 'vip_exclusive.jpg'
elif 'aud_high_value' in segments:
return 'premium_products.jpg'
else:
return 'default_hero.jpg'

Lead Scoring Integration

Automatically update list membership based on lead scores:

# Example: Ruby lead scoring integration
class LeadScoringIntegration
def initialize(api_key)
@api_key = api_key
@api_client = Stack9::Client.new(api_key)
end

def update_lead_segments
# Get all subscribers with scores
subscribers = fetch_scored_leads

# Define score thresholds
segments = {
hot_leads: { min: 80, list_id: 'list_hot_leads' },
warm_leads: { min: 50, max: 79, list_id: 'list_warm_leads' },
cold_leads: { max: 49, list_id: 'list_cold_leads' }
}

# Update list membership
subscribers.each do |subscriber|
score = subscriber[:lead_score]
current_segment = determine_segment(score, segments)

# Remove from other segments
segments.each do |key, config|
next if key == current_segment

@api_client.remove_subscriber_from_list(
list_id: config[:list_id],
subscriber_id: subscriber[:id]
)
end

# Add to appropriate segment
if current_segment
@api_client.add_subscriber_to_list(
list_id: segments[current_segment][:list_id],
subscriber_id: subscriber[:id]
)
end
end
end

private

def determine_segment(score, segments)
segments.each do |key, config|
if config[:min] && config[:max]
return key if score >= config[:min] && score <= config[:max]
elsif config[:min]
return key if score >= config[:min]
elsif config[:max]
return key if score <= config[:max]
end
end
nil
end
end

Troubleshooting

Common Issues

  1. Import Job Stuck in Processing

    • Check file size and format
    • Verify column mappings are correct
    • Review API rate limits
    • Contact support if processing > 2 hours
  2. Duplicate Subscribers

    • Email is the unique identifier
    • Use update_only to avoid duplicates
    • Implement deduplication in source files
  3. Missing Custom Fields

    • Ensure fields are defined in subscriber schema
    • Use correct path notation for nested fields
    • Check field type compatibility

Error Codes

CodeDescriptionSolution
INVALID_AUDIENCEAudience validation failedCheck name uniqueness
LIST_NOT_FOUNDList ID doesn't existVerify list ID
DUPLICATE_EMAILEmail already existsUse update operation
INVALID_IMPORT_FILEFile format not supportedUse CSV or Excel format
JOB_ALREADY_PROCESSINGImport job in progressWait for completion
QUOTA_EXCEEDEDAPI rate limit reachedImplement backoff strategy

Webhooks & Events

Subscribe to real-time events for lists and audiences:

Available Events

  • audience.created: New audience created
  • audience.updated: Audience modified
  • audience.deleted: Audience removed
  • list.created: New list created
  • list.updated: List modified
  • list.deleted: List removed
  • list.import.started: Import job started
  • list.import.completed: Import job finished
  • list.import.failed: Import job failed
  • subscriber.added_to_list: Subscriber joined list
  • subscriber.removed_from_list: Subscriber left list

Event Payload Example

{
"event": "list.import.completed",
"timestamp": "2024-03-15T14:30:00.000Z",
"data": {
"list_id": "list_Rt7mKp3QsU9xNw4",
"job_id": "job_Zq9pRt6UwY5aNx3",
"status": "completed",
"statistics": {
"total_rows": 10000,
"created": 7500,
"updated": 2500,
"errors": 25
}
}
}

Migration Guide

Migrating from Static to Dynamic Lists

  1. Analyze Current Lists: Export all static list members
  2. Define Audience Criteria: Create rules matching current membership
  3. Create Dynamic Audience: Set up automated segmentation
  4. Validate Membership: Compare counts and samples
  5. Switch List Mode: Update from static to dynamic
  6. Monitor Changes: Track membership fluctuations

Bulk Migration Example

#!/bin/bash
# Migrate multiple static lists to dynamic

OLD_LISTS=("list_old_1" "list_old_2" "list_old_3")

for old_list in "${OLD_LISTS[@]}"; do
# Export current members
curl -X GET \
"https://apis.app.stack9.co/api/lists/$old_list/export" \
-H 'X-API-Key: your-api-key-here' \
-o "$old_list_members.csv"

# Create new audience
audience_response=$(curl -X POST \
https://apis.app.stack9.co/api/audiences \
-H 'X-API-Key: your-api-key-here' \
-H 'Content-Type: application/json' \
-d '{
"name": "Migrated: '"$old_list"'"
}')

audience_id=$(echo $audience_response | jq -r '.id')

# Create dynamic list
curl -X POST \
https://apis.app.stack9.co/api/lists \
-H 'X-API-Key: your-api-key-here' \
-H 'Content-Type: application/json' \
-d '{
"name": "Dynamic: '"$old_list"'",
"mode": "dynamic",
"audience_id": "'"$audience_id"'"
}'

echo "Migrated $old_list to dynamic audience $audience_id"
done

Rate Limits & Quotas

OperationRate LimitBurstQuota
Create Audience/List10/minute2010,000/month
Update Audience/List30/minute50Unlimited
Add/Remove Subscriber100/minute200Unlimited
Import Job5/hour101,000/month
List/Search60/minute100Unlimited
Export10/hour20500/month

Rate Limit Headers

All responses include rate limit information:

X-RateLimit-Limit: 100
X-RateLimit-Remaining: 95
X-RateLimit-Reset: 1710510000

Summary

The Marketing Lists & Audiences API provides a powerful foundation for customer segmentation and targeted marketing. By combining dynamic audiences with static lists, supporting bulk operations, and enabling real-time updates, the API empowers marketers to create sophisticated targeting strategies while maintaining performance at scale.

Key capabilities include:

  • Flexible segmentation with static and dynamic options
  • High-performance bulk import with job tracking
  • Real-time subscriber management
  • Comprehensive error handling and reporting
  • Integration-ready with webhooks and events
  • Enterprise-grade reliability and compliance

For additional support, consult the Stack9 API documentation or contact our technical support team.