Progressive engine

One free agent. One next lead. No overdial.

This guide is only the calling brain. Lead ingest lives in the API reference. Overdial and customer-first originate are in the Predictive guide. Both engines originate through AMI.

Panel active Presence ready AMI idle Any idle agent

End-to-end flow

The engine does not poll on a global timer. Every AMI patch, panel join/leave, or ready/pause updates that extension and may schedule a claim. PSTN inbound is off — see Inbound.

  1. Agent socket + AMI state (panel active, presence ready, SIP idle)
  2. Wait buffer_time after the last connected call
  3. Claim next lead (Abandoned first, then priority). Any idle agent
  4. AMI Originate to PJSIP/{extension} with shared AMI_CALLERID
  5. Talk → Received. Miss → Not Connected. Then wrap and claim again

When an agent dials

FlagSourceMust be
panelAgent page connectedactive
presenceReady / pause on the panel (hold_dialer_employee.panel_status)ready
amiAsterisk device stateidle

Also required: no call already in flight, and an employee loaded from this module’s hold_dialer_employee roster. Skills are unused. Ready/pause writes hold_dialer_employee.panel_status. AMI and the dashboard only track roster extensions. After a call, the engine waits buffer_time seconds, then claims again. If no lead is due, it retries every 10 seconds.

Claim order

Two agents cannot take the same row. Claim uses FOR UPDATE SKIP LOCKED, then sets Calling, reserves the lead, and sets first_attempt_at on the first originate. call_count does not increment on claim.

1
Abandoned first
Any Abandoned row sorts above other statuses.
2
Priority number
Lowest priority_no first (Hold Lead is id 1; Hold + Not Connected is id 2).
3
Dial status
Pending, then Callback, then Not Connected.
4
Age
Never attempted first, then oldest attempt, then oldest push, then lowest id.

Any idle ready agent may take any eligible lead. Master has no agent_id pin. Received, Rejected, Calling, and reserved rows are skipped. Claim also waits on next_retry_at and refuses originate outside work_startwork_end except for a due callback.

Callback Request

Callback priorities (is_callback = 1, seeded as id 2) honor callback_scheduled_at. Any idle agent may claim it when due. Full behaviour (time gate, retry) is in the Callback Request guide. How you send the fields is in the API reference.

1
Lead is waiting
Future callback_scheduled_at → skip. Other priorities keep dialing.
2
Time is due
Any idle ready agent may claim it.
3
No time sent
A callback priority without a datetime is Pending and dials like any other hold lead.

Hangup results

HangupStored status
ANSWERReceived
Cancel by customer, invalid destinationRejected
No answer, busy, congestion, chanunavailNot Connected

Received and Rejected are not claimed again. Not Connected uses [2,2,2,2]: four rounds of two tries. The 1st NC of a round waits retry_seconds the same day; the 2nd waits 1, then 7, then 14 days. After the first pair, priority_id becomes 2. At 8 NCs the row is copied to hold_dialer_disposed and deleted from master. Abandoned retries in a fixed 5 minutes and ignores those knobs.

Engine config

SettingWhereMeaning
dialer_typehold_dialer_configProgressive or Predictive
buffer_timehold_dialer_configSeconds between calls per agent
max_trieshold_dialer_configHard cap on Not Connected tries (8)
retry_secondshold_dialer_configSame-day gap after the first NC in a round
retry_patternhold_dialer_configRounds of tries, default [2,2,2,2]
work_start / work_endhold_dialer_configOriginate window, default 09:30–18:30 IST
work_dayshold_dialer_configISO weekdays, default Mon–Sat [1,2,3,4,5,6]
disposed_priority_idhold_dialer_configFinal Disposal — never claimed
AMI_AGENT_CHANNEL.envDefault PJSIP/{extension}
AMI_CALLERID.envShared outbound CLI (never the customer number)
DIAL_ORIGINATE_TIMEOUT_MS.envWait for AMI on_call (default 60s)