Skip to content

How to Create Campaigns via API for Amazon Connect Outbound Campaigns

13 minute read
Content level: Intermediate
0

This guide explains how to programmatically create Amazon Connect Outbound Campaigns using AWS APIs. Since Campaign Flows (Type: CAMPAIGN) cannot be created through the UI, this article provides a complete workflow for extracting Campaign Flows from UI-created campaigns and reusing them in API-based campaign creation. It includes step-by-step AWS CLI commands, sample outputs, parameter explanations, workflow diagrams, and bash automation scripts for end-to-end campaign creation via API.

Understanding Campaign Flows vs Contact Flows

Amazon Connect outbound campaigns require two separate flows:

1. Campaign Flow (Type: CAMPAIGN)

  • Manages campaign execution and engagement logic
  • Contains retry/reattempt logic, delivery receipt evaluation, and engagement preference cycling
  • Referenced via connectCampaignFlowArn in CreateCampaign API
  • Cannot be created through the UI flow designer

2. Contact Flow (Type: CONTACT_FLOW)

  • Defines customer experience when call is answered
  • Contains Polly, Lex, business logic, and conversation flow
  • Referenced via connectContactFlowId in campaign configuration

Key Point: When a call is answered, Amazon Connect automatically routes the customer to the connectContactFlowId. No transfer block is needed in the Campaign Flow.


Architecture Diagram

Enter image description here

Understanding the Architecture:

This diagram illustrates the relationship between Campaign Flow and Contact Flow in Amazon Connect Outbound Campaigns:

Campaign Flow (Blue Section - Type CAMPAIGN):

- Step 1: Campaign starts and initiates the first dial attempt using PutDialRequest

- Step 2: System waits for a fixed period to allow the call to complete

- Step 3: Evaluates delivery receipts to determine call outcome (invalid number, busy, answered, etc.)

- Step 4-5: If invalid number or busy signal detected, waits before retry and attempts next engagement preference

- Step 6: Terminates execution with EndFlowExecution

Contact Flow (Orange Section - Type CONTACT_FLOW):

  • This is an example only - you define your own customer experience
  • When a call is answered, Amazon Connect automatically routes the customer here
  • Can contain any blocks needed for your use case (Polly, Lex, business logic, etc.)
  • The example shows a simple flow, but yours can be much more complex

Key Integration Point:

  • The dotted line "Call Answered" shows the automatic routing from Campaign Flow to Contact Flow
  • No transfer block is needed - Amazon Connect handles this automatically
  • The Campaign Flow manages dialing and retries; the Contact Flow handles the conversation

Complete Workflow Diagram

Enter image description here

Understanding the Workflow:

This sequence diagram shows the complete 8-step process for extracting and reusing Campaign Flows:

Phase 1: Extract Existing Campaign Flow (Steps 1-2)

- Step 1: Create a template campaign through the Amazon Connect UI with your desired retry settings

- Step 2: Use AWS CLI to describe the campaign and extract the connectCampaignFlowArn

- Purpose: Get the ARN of an existing Campaign Flow that contains the retry logic you want to reuse

Phase 2: Get Flow Content (Steps 3-5)

- Step 3: Extract the flow ID from the ARN

- Step 4: Use describe-contact-flow to retrieve the complete flow definition

- Step 5: Save the Content JSON to a file for reuse

- Purpose: Extract the actual flow definition (blocks, transitions, parameters) that you'll use to create new flows

Phase 3: Create New Campaign Flow (Steps 6-7)

- Step 6: Use create-contact-flow with type CAMPAIGN to create your reusable flow

- Step 7: Verify the flow is PUBLISHED and ACTIVE

- Purpose: Create a new Campaign Flow that you can use across multiple campaigns

Phase 4: Create Campaign (Step 8)

- Step 8: Use create-campaign with your new Campaign Flow ARN

- Purpose: Create a new campaign programmatically using your reusable Campaign Flow


Implementation Steps

Step 1: Create a Template Campaign via UI

  1. Log into Amazon Connect console
  2. Navigate to Outbound campaigns
  3. Create a new campaign with your desired retry settings
  4. Configure reattempt rules (e.g., retry on busy, invalid number)
  5. Save the campaign

Step 2: Describe the Campaign to Get Flow ARN

Command:

aws connectcampaignsv2 describe-campaign \
    --id your-campaign-id

Sample Output:

{
    "campaign": {
        "id": "campaign-id-example",
        "arn": "arn:aws:connect-campaigns:us-east-1:123456789012:campaign/campaign-id-example",
        "name": "my-test-campaign",
        "connectInstanceId": "instance-id-example",
        "connectCampaignFlowArn": "arn:aws:connect:us-east-1:123456789012:instance/instance-id-example/contact-flow/flow-campaign-example",
        "channelSubtypeConfig": {
            "telephony": {
                "capacity": 1.0,
                "connectQueueId": "queue-id-example",
                "defaultOutboundConfig": {
                    "connectContactFlowId": "contact-flow-id-example",
                    "connectSourcePhoneNumber": "+1-555-0100",
                    "answerMachineDetectionConfig": {
                        "enableAnswerMachineDetection": true,
                        "awaitAnswerMachinePrompt": true
                    }
                },
                "outboundMode": {
                    "agentless": {}
                }
            }
        },
        "source": {
            "customerProfilesSegmentArn": "arn:aws:profile:us-east-1:123456789012:domains/domain-id/segments/segment-name"
        },
        "schedule": {
            "startTime": "2025-12-02T19:30:00Z",
            "endTime": "2025-12-03T20:30:00Z"
        }
    }
}

Key Parameters Explained:

  • id: Unique identifier for the campaign
  • connectCampaignFlowArn: ARN of the CAMPAIGN flow that manages execution logic (THIS IS WHAT YOU NEED)
  • connectContactFlowId: ID of the CONTACT_FLOW that handles customer experience
  • capacity: Dialing capacity allocation (0.01 to 1.0)
  • answerMachineDetectionConfig: AMD settings for detecting voicemail
  • outboundMode.agentless: Indicates agentless campaign mode

Record the connectCampaignFlowArn


Step 3: Extract the Contact Flow ID

From the ARN, extract the flow ID (the last segment after /contact-flow/).

Using bash to extract:

FLOW_ID=$(echo "your-campaign-flow-arn" | awk -F'/' '{print $NF}')
echo $FLOW_ID

Step 4: Describe the Contact Flow to Get Content

Command:

aws connect describe-contact-flow \
    --instance-id your-instance-id \
    --contact-flow-id flow-id-from-step-3

Sample Output:

{
    "ContactFlow": {
        "Arn": "arn:aws:connect:us-east-1:123456789012:instance/instance-id-example/contact-flow/flow-campaign-example",
        "Id": "flow-campaign-example",
        "Name": "flow-campaign-example",
        "Type": "CAMPAIGN",
        "State": "ACTIVE",
        "Status": "PUBLISHED",
        "Description": "Flow designed to handle execution for the outbound campaign",
        "Content": "{\"Version\":\"2019-10-30\",\"StartAction\":\"FirstMessageSend\",\"Actions\":[...]}",
        "Tags": {},
        "FlowContentSha256": "abc123def456",
        "LastModifiedTime": "2025-12-01T04:14:13.693000+00:00",
        "LastModifiedRegion": "us-east-1"
    }
}

Key Parameters Explained:

  • Type: Must be "CAMPAIGN" for campaign flows
  • State: "ACTIVE" means the flow is available for use
  • Status: "PUBLISHED" means the flow is ready for campaigns
  • Content: JSON string containing the flow definition (this is what you'll reuse)
  • FlowContentSha256: Hash for version tracking
  • LastModifiedTime: Timestamp of last modification

Step 5: Extract and Save the Content

Using jq to extract just the Content field:

aws connect describe-contact-flow \
    --instance-id your-instance-id \
    --contact-flow-id flow-id-from-step-3 \
    --query 'ContactFlow.Content' \
    --output text > campaign-flow-content.json

The saved file contains the complete flow definition with all blocks, transitions, and parameters.


Step 6: Create Your Own Campaign Flow

Command:

aws connect create-contact-flow \
    --instance-id your-instance-id \
    --name "my-reusable-campaign-flow" \
    --content file://campaign-flow-content.json \
    --type CAMPAIGN \
    --description "Reusable campaign flow with retry logic"

Sample Output:

{
    "ContactFlowId": "new-flow-id-example",
    "ContactFlowArn": "arn:aws:connect:us-east-1:123456789012:instance/instance-id-example/contact-flow/new-flow-id-example"
}

Output Parameters Explained:

  • ContactFlowId: Unique identifier for the newly created flow
  • ContactFlowArn: Full ARN of the flow (use this in connectCampaignFlowArn)

Record the ContactFlowArn - this is what you'll use in your campaigns.


Step 7: Verify Your Campaign Flow

Command:

aws connect describe-contact-flow \
    --instance-id your-instance-id \
    --contact-flow-id ContactFlowId-from-step-6

Verification Checklist:

  • Type: "CAMPAIGN"
  • Status: "PUBLISHED"
  • State: "ACTIVE"

Step 8: Create a Campaign Using Your Campaign Flow

Once you have created your Campaign Flow, you can use it to create campaigns programmatically.

channel-config.json:

{
  "telephony": {
    "capacity": 1.0,
    "connectQueueId": "queue-id-example",
    "outboundMode": {
      "agentless": {}
    },
    "defaultOutboundConfig": {
      "connectContactFlowId": "contact-flow-id-example",
      "connectSourcePhoneNumber": "+1-555-0100",
      "answerMachineDetectionConfig": {
        "enableAnswerMachineDetection": true,
        "awaitAnswerMachinePrompt": true
      }
    }
  }
}

source-config.json:

{
  "customerProfilesSegmentArn": "arn:aws:profile:us-east-1:123456789012:domains/domain-id/segments/segment-name"
}

schedule-config.json:

{
  "startTime": "2025-12-02T19:30:00Z",
  "endTime": "2025-12-03T20:30:00Z"
}

time-config.json:

{
  "localTimeZoneConfig": {
    "defaultTimeZone": "America/New_York",
    "localTimeZoneDetection": ["AREA_CODE", "ZIP_CODE"]
  },
  "telephony": {
    "openHours": {
      "dailyHours": {
        "MONDAY": [{"startTime": "T09:00", "endTime": "T17:00"}],
        "TUESDAY": [{"startTime": "T09:00", "endTime": "T17:00"}],
        "WEDNESDAY": [{"startTime": "T09:00", "endTime": "T17:00"}],
        "THURSDAY": [{"startTime": "T09:00", "endTime": "T17:00"}],
        "FRIDAY": [{"startTime": "T09:00", "endTime": "T17:00"}]
      }
    },
    "restrictedPeriods": {
      "restrictedPeriodList": [
        {
          "name": "Holiday Period",
          "startDate": "2025-12-24",
          "endDate": "2025-12-26"
        }
      ]
    }
  }
}

limits-config.json:

{
  "allChannelSubtypes": {
    "communicationLimitsList": [
      {
        "maxCountPerRecipient": 3,
        "frequency": 1,
        "unit": "DAY"
      }
    ]
  },
  "instanceLimitsHandling": "OPT_OUT"
}

Complete Command:

aws connectcampaignsv2 create-campaign \
    --name "my-automated-campaign" \
    --connect-instance-id your-instance-id \
    --connect-campaign-flow-arn "ContactFlowArn-from-step-6" \
    --channel-subtype-config file://channel-config.json \
    --source file://source-config.json \
    --schedule file://schedule-config.json \
    --communication-time-config file://time-config.json \
    --communication-limits-override file://limits-config.json \
    --tags owner=arn:aws:connect:us-east-1:123456789012:instance/your-instance-id

Sample Output:

{
    "id": "campaign-id-example",
    "arn": "arn:aws:connect-campaigns:us-east-1:123456789012:campaign/campaign-id-example",
    "tags": {
        "owner": "arn:aws:connect:us-east-1:123456789012:instance/instance-id-example"
    }
}

Output Parameters Explained:

  • id: Unique campaign identifier (use this to start/stop/manage the campaign)
  • arn: Full ARN of the campaign
  • tags: Tags associated with the campaign

Understanding Engagement Preference Cycling

Campaign Flows automatically cycle through customer engagement preferences defined in Amazon Connect Customer Profiles.

What are Engagement Preferences?

Engagement preferences specify the customer's preferred contact methods in priority order:

  • HomePhoneNumber
  • MobilePhoneNumber
  • BusinessPhoneNumber
  • PersonalEmailAddress
  • BusinessEmailAddress

How Automatic Cycling Works:

Enter image description here

This sequence diagram illustrates how Amazon Connect automatically manages engagement preference progression using a 3-preference example scenario:

Example Scenario (3 Preferences):

Attempt 1 (Index 0):

  • Campaign Flow requests the first engagement preference (index 0)
  • Customer Profiles returns MobilePhoneNumber
  • Campaign Flow dials the number
  • Customer responds with SIT_TONE_INVALID_NUMBER (invalid number detected)
  • System waits before next attempt

Attempt 2 (Index 1):

  • Campaign Flow automatically requests the next preference (index 1)
  • Customer Profiles returns HomePhoneNumber
  • Campaign Flow dials the number
  • Customer responds with SIT_TONE_BUSY (line is busy)
  • System waits before next attempt

Attempt 3 (Index 2):

  • Campaign Flow automatically requests the next preference (index 2)
  • Customer Profiles returns BusinessPhoneNumber
  • Campaign Flow dials the number
  • Customer answers the call successfully
  • Customer is automatically connected to the Contact Flow for the conversation

Important Notes:

  1. This is an example - Customers may have 1, 2, 3, or more engagement preferences
  2. Single preference customers - If a customer has only one preference, the system will retry that preference based on delivery receipt evaluation
  3. Empty PutDialRequest parameters ({}) - Amazon Connect automatically manages preference progression regardless of how many preferences exist
  4. Per-recipient tracking - Each customer's preference cycling is independent based on their profile
  5. Wait periods between attempts allow for proper retry timing
  6. Delivery receipt evaluation determines when to retry vs. when to move to next preference

Complete End-to-End Bash Script

#!/bin/bash
set -e

# Configuration - REPLACE WITH YOUR VALUES
INSTANCE_ID="your-instance-id"
EXISTING_CAMPAIGN_ID="your-existing-campaign-id"
NEW_FLOW_NAME="my-reusable-campaign-flow"
NEW_CAMPAIGN_NAME="my-automated-campaign"
QUEUE_ID="your-queue-id"
CONTACT_FLOW_ID="your-contact-flow-id"
SOURCE_PHONE="your-phone-number"
SEGMENT_ARN="your-segment-arn"

echo "========================================="
echo "Campaign Flow Extraction and Creation"
echo "========================================="

# Step 1: Describe existing campaign
echo ""
echo "[Step 1] Describing existing campaign..."
aws connectcampaignsv2 describe-campaign --id $EXISTING_CAMPAIGN_ID > campaign-details.json
echo "✓ Campaign details saved"

# Step 2: Extract campaign flow ARN
echo ""
echo "[Step 2] Extracting campaign flow ARN..."
CAMPAIGN_FLOW_ARN=$(jq -r '.campaign.connectCampaignFlowArn' campaign-details.json)
echo "Campaign Flow ARN: $CAMPAIGN_FLOW_ARN"

# Step 3: Extract flow ID
echo ""
echo "[Step 3] Extracting flow ID..."
FLOW_ID=$(echo $CAMPAIGN_FLOW_ARN | awk -F'/' '{print $NF}')
echo "Flow ID: $FLOW_ID"

# Step 4: Get flow content
echo ""
echo "[Step 4] Retrieving flow content..."
aws connect describe-contact-flow --instance-id $INSTANCE_ID --contact-flow-id $FLOW_ID > flow-details.json
echo "✓ Flow details saved"

# Step 5: Extract content
echo ""
echo "[Step 5] Extracting flow content..."
jq -r '.ContactFlow.Content' flow-details.json > campaign-flow-content.json
echo "✓ Flow content saved"

# Step 6: Create new campaign flow
echo ""
echo "[Step 6] Creating new campaign flow..."
CREATE_RESPONSE=$(aws connect create-contact-flow --instance-id $INSTANCE_ID --name "$NEW_FLOW_NAME" --content file://campaign-flow-content.json --type CAMPAIGN --description "Reusable campaign flow with retry logic")

NEW_FLOW_ARN=$(echo $CREATE_RESPONSE | jq -r '.ContactFlowArn')
NEW_FLOW_ID=$(echo $CREATE_RESPONSE | jq -r '.ContactFlowId')
echo "✓ New Flow ARN: $NEW_FLOW_ARN"

# Step 7: Verify
echo ""
echo "[Step 7] Verifying flow..."
aws connect describe-contact-flow --instance-id $INSTANCE_ID --contact-flow-id $NEW_FLOW_ID > new-flow-verification.json

FLOW_TYPE=$(jq -r '.ContactFlow.Type' new-flow-verification.json)
FLOW_STATUS=$(jq -r '.ContactFlow.Status' new-flow-verification.json)
FLOW_STATE=$(jq -r '.ContactFlow.State' new-flow-verification.json)

echo "✓ Flow Type: $FLOW_TYPE"
echo "✓ Flow Status: $FLOW_STATUS"
echo "✓ Flow State: $FLOW_STATE"

# Step 8: Create campaign configuration files
echo ""
echo "[Step 8] Creating campaign..."

# Create channel config
cat > channel-config.json <<EOF
{
  "telephony": {
    "capacity": 1.0,
    "connectQueueId": "$QUEUE_ID",
    "outboundMode": {
      "agentless": {}
    },
    "defaultOutboundConfig": {
      "connectContactFlowId": "$CONTACT_FLOW_ID",
      "connectSourcePhoneNumber": "$SOURCE_PHONE",
      "answerMachineDetectionConfig": {
        "enableAnswerMachineDetection": true,
        "awaitAnswerMachinePrompt": true
      }
    }
  }
}
EOF

# Create source config
cat > source-config.json <<EOF
{
  "customerProfilesSegmentArn": "$SEGMENT_ARN"
}
EOF

# Create schedule config
TOMORROW=$(date -u -d "+1 day" +"%Y-%m-%dT19:30:00Z")
DAY_AFTER=$(date -u -d "+2 days" +"%Y-%m-%dT20:30:00Z")
cat > schedule-config.json <<EOF
{
  "startTime": "$TOMORROW",
  "endTime": "$DAY_AFTER"
}
EOF

# Create campaign
CAMPAIGN_RESPONSE=$(aws connectcampaignsv2 create-campaign --name "$NEW_CAMPAIGN_NAME" --connect-instance-id $INSTANCE_ID --connect-campaign-flow-arn "$NEW_FLOW_ARN" --channel-subtype-config file://channel-config.json --source file://source-config.json --schedule file://schedule-config.json --tags owner=arn:aws:connect:us-east-1:123456789012:instance/$INSTANCE_ID)

CAMPAIGN_ID=$(echo $CAMPAIGN_RESPONSE | jq -r '.id')
CAMPAIGN_ARN=$(echo $CAMPAIGN_RESPONSE | jq -r '.arn')

echo "✓ Campaign created successfully"
echo "  Campaign ID: $CAMPAIGN_ID"
echo "  Campaign ARN: $CAMPAIGN_ARN"

echo ""
echo "========================================="
echo "✅ Process completed successfully!"
echo "========================================="
echo ""
echo "Campaign Flow ARN:"
echo "$NEW_FLOW_ARN"
echo ""
echo "Campaign ID:"
echo "$CAMPAIGN_ID"
echo ""
echo "Files created:"
echo "  - campaign-details.json"
echo "  - flow-details.json"
echo "  - campaign-flow-content.json"
echo "  - new-flow-verification.json"
echo "  - channel-config.json"
echo "  - source-config.json"
echo "  - schedule-config.json"

Troubleshooting: Common Bash Script Issues

If you encounter errors when running the bash script, try these solutions:

Issue 1: Windows Line Endings (CRLF)

Symptoms:

: invalid option
$'\r': command not found

Cause: Script was created/edited on Windows with CRLF line endings instead of Unix LF line endings.

Solution 1 - Using dos2unix (Recommended):

# Install dos2unix
sudo yum install dos2unix  # Amazon Linux/RHEL/CentOS
# or
sudo apt-get install dos2unix  # Ubuntu/Debian

# Convert the file
dos2unix your-script.sh

# Run the script
bash your-script.sh

Solution 2 - Using sed:

sed -i 's/\r$//' your-script.sh
bash your-script.sh

Solution 3 - Using tr:

tr -d '\r' < your-script.sh > your-script-fixed.sh
chmod +x your-script-fixed.sh
bash your-script-fixed.sh

Solution 4 - Recreate on Linux:

# Create new file directly on Linux
nano your-script.sh
# Paste content, save with Ctrl+X, Y, Enter
chmod +x your-script.sh
bash your-script.sh

Issue 2: Missing jq Command

Symptoms:

jq: command not found

Solution:

# Amazon Linux/RHEL/CentOS
sudo yum install jq

# Ubuntu/Debian
sudo apt-get install jq

# macOS
brew install jq

Issue 3: AWS CLI Not Configured

Symptoms:

Unable to locate credentials

Solution:

aws configure
# Enter your AWS Access Key ID
# Enter your Secret Access Key
# Enter default region (e.g., us-east-1)
# Enter default output format (json)

Issue 4: Permission Denied

Symptoms:

bash: ./your-script.sh: Permission denied

Solution:

chmod +x your-script.sh
./your-script.sh

Issue 5: Script Debugging

To see detailed execution (helpful for troubleshooting):

bash -x your-script.sh

To check for syntax errors without running:

bash -n your-script.sh

Best Practices

  1. Reuse Campaign Flows: One Campaign Flow can be shared across multiple campaigns
  2. Separate Concerns: Keep campaign execution logic in CAMPAIGN flows, customer experience in CONTACT_FLOW
  3. Test Thoroughly: Create a test campaign via UI first to validate retry logic
  4. Document Your Flows: Add meaningful descriptions when creating flows
  5. Monitor Performance: Use CloudWatch metrics to track campaign execution
  6. Tag for UI Visibility: Add instance ID as a tag to make campaigns visible in the UI

Documentation References