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
| Parameter | Type | Required | Description |
|---|---|---|---|
name | string | Yes | Unique, 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
| Parameter | Type | Required | Description |
|---|---|---|---|
page | number | Yes | Page number (1-based) |
limit | number | Yes | Items per page (max: 100) |
search | string | No | Search audiences by name |
filters | object | No | Filter criteria object |
filters.name | object | No | Filter by audience name |
filters.id | object | No | Filter by audience ID |
filters.created_at | object | No | Filter by creation date |
filters.updated_at | object | No | Filter by last update date |
Filter Operations
Each filter field supports the following operations:
eq: Equalsne: Not equalslike: Contains (case-insensitive)in: In array of valuesbetween: 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
| Parameter | Type | Required | Description |
|---|---|---|---|
audience_id | string | Yes | The 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
| Parameter | Type | Required | Description |
|---|---|---|---|
id | string | Yes | The audience's unique identifier |
name | string | Yes | New 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
| Parameter | Type | Required | Description |
|---|---|---|---|
audience_id | string | Yes | The 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
| Parameter | Type | Required | Description |
|---|---|---|---|
audience_id | string | Yes | The audience's unique identifier |
subscriber_id | string | Yes | The 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
| Parameter | Type | Required | Description |
|---|---|---|---|
audience_id | string | Yes | The audience's unique identifier |
subscriber_id | string | Yes | The 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
| Parameter | Type | Required | Description |
|---|---|---|---|
name | string | Yes | Memorable name for the list |
mode | string | Yes | List mode: static or dynamic |
audience_id | string | Yes | Associated audience ID (use default if none) |
jobs | array | No | Import 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
| Parameter | Type | Required | Description |
|---|---|---|---|
page | number | Yes | Page number (1-based) |
limit | number | Yes | Items per page (max: 100) |
search | string | No | Search lists by name |
filters | object | No | Filter criteria object |
filters.id | object | No | Filter by list ID |
filters.name | object | No | Filter by list name |
filters.mode | object | No | Filter by mode (static/dynamic) |
filters.audience_id | object | No | Filter by associated audience |
filters.created_at | object | No | Filter by creation date |
filters.updated_at | object | No | Filter 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
| Parameter | Type | Required | Description |
|---|---|---|---|
list_id | string | Yes | The 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
| Parameter | Type | Required | Description |
|---|---|---|---|
id | string | Yes | The list's unique identifier |
name | string | Yes | New name for the list |
jobs | array | No | Import 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
| Parameter | Type | Required | Description |
|---|---|---|---|
list_id | string | Yes | The 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
| Parameter | Type | Required | Description |
|---|---|---|---|
list_id | string | Yes | The list's unique identifier |
subscriber_id | string | Yes | The 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
| Parameter | Type | Required | Description |
|---|---|---|---|
list_id | string | Yes | The list's unique identifier |
subscriber_id | string | Yes | The 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
| Parameter | Type | Required | Description |
|---|---|---|---|
list_id | string | Yes | The list's unique identifier |
file_url | string | Yes | URL of the uploaded CSV/Excel file |
import_type | string | Yes | Import operation type |
columns_mapping | object | No | Map CSV columns to subscriber fields |
Import Types
create_only: Only create new subscribers, skip existingupdate_only: Only update existing subscribers, skip newcreate_update: Create new and update existing subscribersremove_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
| Parameter | Type | Required | Description |
|---|---|---|---|
list_id | string | Yes | The list's unique identifier |
page | number | No | Page number (default: 1) |
limit | number | No | Items 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
| Parameter | Type | Required | Description |
|---|---|---|---|
list_id | string | Yes | The list's unique identifier |
job_id | string | Yes | The 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 processingprocessing: Actively importing/processing recordscompleted: Successfully finished all operationscancelled: 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
- Audience Hierarchy: Create broad audiences and use lists for specific campaigns
- Naming Conventions: Use descriptive, consistent naming patterns
- Regular Cleanup: Archive or delete unused segments quarterly
- Performance Testing: Test segment queries with small samples first
- Documentation: Document segment criteria and business logic
Import Operations
-
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
-
Column Mapping:
- Map all required fields explicitly
- Use dot notation for nested custom fields
- Validate date formats match ISO 8601
-
Error Handling:
- Always download and review error reports
- Implement retry logic for temporary failures
- Keep original files for audit purposes
Performance Optimization
-
Batch Operations:
- Use bulk import instead of individual API calls
- Process large lists during off-peak hours
- Implement pagination for large result sets
-
Caching Strategy:
- Cache audience/list metadata locally
- Refresh cache on webhook events
- Use ETags for conditional requests
-
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
-
Data Governance:
- Implement retention policies for inactive subscribers
- Track consent status in custom fields
- Maintain suppression lists for opt-outs
-
Audit Trail:
- Log all list modifications
- Track import job history
- Document segment criteria changes
-
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
-
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
-
Duplicate Subscribers
- Email is the unique identifier
- Use
update_onlyto avoid duplicates - Implement deduplication in source files
-
Missing Custom Fields
- Ensure fields are defined in subscriber schema
- Use correct path notation for nested fields
- Check field type compatibility
Error Codes
| Code | Description | Solution |
|---|---|---|
INVALID_AUDIENCE | Audience validation failed | Check name uniqueness |
LIST_NOT_FOUND | List ID doesn't exist | Verify list ID |
DUPLICATE_EMAIL | Email already exists | Use update operation |
INVALID_IMPORT_FILE | File format not supported | Use CSV or Excel format |
JOB_ALREADY_PROCESSING | Import job in progress | Wait for completion |
QUOTA_EXCEEDED | API rate limit reached | Implement backoff strategy |
Webhooks & Events
Subscribe to real-time events for lists and audiences:
Available Events
audience.created: New audience createdaudience.updated: Audience modifiedaudience.deleted: Audience removedlist.created: New list createdlist.updated: List modifiedlist.deleted: List removedlist.import.started: Import job startedlist.import.completed: Import job finishedlist.import.failed: Import job failedsubscriber.added_to_list: Subscriber joined listsubscriber.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
- Analyze Current Lists: Export all static list members
- Define Audience Criteria: Create rules matching current membership
- Create Dynamic Audience: Set up automated segmentation
- Validate Membership: Compare counts and samples
- Switch List Mode: Update from static to dynamic
- 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
| Operation | Rate Limit | Burst | Quota |
|---|---|---|---|
| Create Audience/List | 10/minute | 20 | 10,000/month |
| Update Audience/List | 30/minute | 50 | Unlimited |
| Add/Remove Subscriber | 100/minute | 200 | Unlimited |
| Import Job | 5/hour | 10 | 1,000/month |
| List/Search | 60/minute | 100 | Unlimited |
| Export | 10/hour | 20 | 500/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.