Skip to main content

AutoDialerCampaign Model

Overview

The AutoDialerCampaign model represents an outbound dialing campaign with configuration for routing, scheduling, rate limiting, and Caller ID Pooling.

Table: auto_dialer_campaigns
Model: App\Models\AutoDialerCampaign
Resource: App\Http\Resources\AutoDialerCampaignResource

Database Schema

ColumnTypeNullableDefaultDescription
idbigint unsignedNoautoPrimary key
organization_idbigint unsignedNo-Foreign key to organizations
namevarchar(255)No-Campaign name
descriptiontextYesnullCampaign description
statusvarchar(20)NodraftCampaign status enum
auto_startbooleanNofalseAuto-start when ready
routing_destination_typevarchar(50)No-ai_assistant, ai_load_balancer, hangup
routing_destination_idbigint unsignedYesnullTarget destination ID
dial_timeoutintNo60Seconds to ring before timeout
destination_connectvarchar(20)Noconnectedconnected or immediately
caller_idvarchar(50)YesnullDefault Caller ID (legacy)
caller_id_strategyvarchar(20)Noround_robinDistribution strategy
caller_id_pool_enabledbooleanNofalseWhether pool mode is enabled
max_dial_attemptsintNo1Max retries per destination
concurrent_active_callsintNo1Max concurrent calls (CAC)
calls_per_secondintNo1Call initiation rate (CPS)
days_activejsonYesnullLegacy schedule days
start_timeintYesnullLegacy start hour
end_timeintYesnullLegacy end hour
start_datedateYesnullCampaign start date
end_datedateYesnullCampaign end date
timezonevarchar(50)YesUTCSchedule timezone
schedulejsonYesnullFull weekly schedule
time_limitintYesnullMax call duration (seconds)
record_callsbooleanNofalseEnable recording
amd_enabledbooleanNofalseEnable AMD
amd_modevarchar(20)YesnullEnabled or DetectMessageEnd
amd_timeoutintYesnullAMD detection timeout
amd_speech_thresholdintYesnullSpeech threshold (ms)
amd_speech_end_thresholdintYesnullSpeech end threshold (ms)
amd_silence_timeoutintYesnullSilence timeout (ms)
total_destinationsintNo0Total destinations count
completed_callsintNo0Completed calls count
failed_callsintNo0Failed calls count
pending_callsintNo0Pending calls count
pause_reasonvarchar(50)YesnullReason for pause
resume_attimestampYesnullScheduled resume time
started_attimestampYesnullWhen campaign started
completed_attimestampYesnullWhen campaign completed
created_attimestampYesnullCreation timestamp
updated_attimestampYesnullLast update timestamp

Relationships

Belongs To

campaign.organization() → Organization

Has Many

campaign.destinations() → AutoDialerDestination[]
campaign.callSessions() → AutoDialerCallSession[]
campaign.lists() → AutoDialerList[] (via pivot)
campaign.callerIdStats() → AutoDialerCallerIdStat[]

Belongs To Many

campaign.callerIds() → DidNumber[]
- Pivot: auto_dialer_campaign_caller_ids
- With pivot: weight

Enums

CampaignStatus

  • draft - Initial configuration
  • active - Currently dialing
  • paused - Temporarily stopped
  • completed - All destinations processed
  • archived - Soft-deleted

RoutingDestinationType

  • ai_assistant - Route to AI Assistant
  • ai_load_balancer - Route via ALBS
  • hangup - Hang up immediately

DestinationConnect

  • connected - Connect when call answered
  • immediately - Connect immediately

AmdMode

  • Enabled - Basic AMD detection
  • DetectMessageEnd - Wait for greeting end

Caller ID Pooling

Configuration

Enable Pool Mode:

$campaign->update([
'caller_id_pool_enabled' => true,
'caller_id_strategy' => 'round_robin', // or 'random', 'least_recently_used'
]);

Assign Caller IDs:

$syncData = [
$didId1 => ['weight' => 1],
$didId2 => ['weight' => 1],
$didId3 => ['weight' => 1],
];
$campaign->callerIds()->sync($syncData);

Strategies

StrategyDescriptionUse Case
round_robinSequential cyclingFair distribution
randomRandom selectionLoad balancing
least_recently_usedPick least usedEven wear

Methods

Scopes

// Organization-scoped (automatic via OrganizationScope)
AutoDialerCampaign::forOrganization($orgId)

// Status filters
AutoDialerCampaign::active()
AutoDialerCampaign::paused()
AutoDialerCampaign::draft()
AutoDialerCampaign::runnable() // Can be started

Business Logic

// Check if campaign can run
$campaign->isRunnable(): bool

// Get progress percentage
$campaign->getProgressPercentage(): float

// Calculate API interval from CPS
$campaign->getApiIntervalMilliseconds(): int

// Check valid CPS
$campaign->hasValidCps(): bool

// Check if has list assigned
$campaign->hasList(): bool

Lifecycle Methods

// Start campaign
$campaign->start(): void

// Pause campaign
$campaign->pause(string $reason, ?DateTime $resumeAt = null): void

// Resume campaign
$campaign->resume(): void

// Archive campaign
$campaign->archive(): void

// Mark as completed
$campaign->complete(): void

Validation Rules

Create/Update

FieldRules
namerequired, string, max:255
caller_id_poolarray, min:1, max:100 (when pool enabled)
caller_id_pool.*.did_idrequired, exists:did_numbers,id
caller_id_strategyrequired, in:round_robin,random,least_recently_used
concurrent_active_callsrequired, integer, min:1, max:50
calls_per_secondrequired, integer, min:1, max:5

Events

The model dispatches events for state changes:

  • CampaignStarted
  • CampaignPaused
  • CampaignResumed
  • CampaignCompleted
  • CampaignArchived

Example Usage

use App\Models\AutoDialerCampaign;
use App\Enums\CampaignStatus;
use App\Enums\RoutingDestinationType;

// Create with Caller ID Pool
$campaign = AutoDialerCampaign::create([
'organization_id' => $orgId,
'name' => 'Sales Campaign Q2',
'status' => CampaignStatus::DRAFT,
'routing_destination_type' => RoutingDestinationType::AI_ASSISTANT,
'routing_destination_id' => $assistantId,
'caller_id_pool_enabled' => true,
'caller_id_strategy' => 'round_robin',
'concurrent_active_calls' => 10,
'calls_per_second' => 2,
'schedule' => [...],
'start_date' => '2026-04-01',
'end_date' => '2026-04-30',
'timezone' => 'America/New_York',
]);

// Assign Caller IDs
$campaign->callerIds()->sync([
$did1->id => ['weight' => 1],
$did2->id => ['weight' => 1],
$did3->id => ['weight' => 1],
]);

// Start campaign
$campaign->start();