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.
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.
- Agent socket + AMI state (panel active, presence ready, SIP idle)
- Wait buffer_time after the last connected call
- Claim next lead (Abandoned first, then priority). Any idle agent
- AMI Originate to PJSIP/{extension} with shared AMI_CALLERID
- Talk → Received. Miss → Not Connected. Then wrap and claim again
When an agent dials
| Flag | Source | Must be |
|---|---|---|
panel | Agent page connected | active |
presence | Ready / pause on the panel (hold_dialer_employee.panel_status) | ready |
ami | Asterisk device state | idle |
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.
Any Abandoned row sorts above other statuses.
Lowest
priority_no first (Hold Lead is id 1; Hold + Not Connected is id 2).Pending, then Callback, then Not Connected.
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_start–work_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.
Future
callback_scheduled_at → skip. Other priorities keep dialing.Any idle ready agent may claim it.
A callback priority without a datetime is Pending and dials like any other hold lead.
Hangup results
| Hangup | Stored status |
|---|---|
ANSWER | Received |
| Cancel by customer, invalid destination | Rejected |
| No answer, busy, congestion, chanunavail | Not 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
| Setting | Where | Meaning |
|---|---|---|
dialer_type | hold_dialer_config | Progressive or Predictive |
buffer_time | hold_dialer_config | Seconds between calls per agent |
max_tries | hold_dialer_config | Hard cap on Not Connected tries (8) |
retry_seconds | hold_dialer_config | Same-day gap after the first NC in a round |
retry_pattern | hold_dialer_config | Rounds of tries, default [2,2,2,2] |
work_start / work_end | hold_dialer_config | Originate window, default 09:30–18:30 IST |
work_days | hold_dialer_config | ISO weekdays, default Mon–Sat [1,2,3,4,5,6] |
disposed_priority_id | hold_dialer_config | Final Disposal — never claimed |
AMI_AGENT_CHANNEL | .env | Default PJSIP/{extension} |
AMI_CALLERID | .env | Shared outbound CLI (never the customer number) |
DIAL_ORIGINATE_TIMEOUT_MS | .env | Wait for AMI on_call (default 60s) |