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.