> ## Documentation Index
> Fetch the complete documentation index at: https://docs.orbit.devotel.io/llms.txt
> Use this file to discover all available pages before exploring further.

# Troubleshooting: dialer preview, power, and predictive modes not advancing

> Resolve preview claims that never advance, claims returning 404, predictive AMD storms, and power-mode idle — map each symptom to the gate that fired and the exact fix.

# Troubleshooting: dialer preview, power, and predictive modes not advancing

A dialer campaign that stops pulling contacts fails in one of a small
number of ways — the claim returns nothing, the claim returns an error,
the scheduler paces but no legs originate, or the campaign pauses
itself. Every failure in this class is decidable from the mode the
campaign runs in and the exact response the dialer API returns. This
page maps symptom to cause to fix per mode.

The full launch sequence, pacing knobs, and disposal matrix are on
[Launch an outbound dialer campaign](/guides/outbound-dialer-campaign).
This page works the failures, not the setup.

## Mode decoder — who dials, and when

The Dialer API exposes two agent-facing endpoints. The other two modes
progress without them.

| Mode                    | Who originates the call | How it advances                                                                                                                                                                                                                                                                                     |
| ----------------------- | ----------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `preview`               | A human agent           | The agent polls `GET /api/v1/dialer/next-call` to atomically claim the next contact, reviews it, then launches the call with `POST /api/v1/dialer/dial`. A claimed contact that sits undecided past the campaign's decision countdown drops back into the eligible pool for another agent to claim. |
| `progressive` ("power") | The pacing scheduler    | One live dial per ready agent — the scheduler originates as soon as an agent signals the queue. Agents never call `next-call` or `dial`; both return `204` on this mode.                                                                                                                            |
| `predictive`            | The pacing scheduler    | The scheduler over-dials by the campaign's `pacing_ratio` (0.8–3.0) per ready agent, bounded by the abandonment ceiling. Same rule as progressive: `next-call` and `dial` are not for this mode.                                                                                                    |
| `agentless`             | The pacing scheduler    | Broadcast — the scheduler originates and plays the campaign's `broadcast_message_url`. No agent leg exists.                                                                                                                                                                                         |

Two consequences follow from this table that resolve most "stuck
campaign" reports before any deeper triage:

* **Preview is the only mode where an agent's poll drives the
  campaign.** If no agent polls `next-call`, a preview campaign claims
  nothing and the list sits at `pending` forever. Progressive and
  predictive campaigns keep dialing as long as the scheduler sees a
  ready agent and eligible contacts.
* **A `204` from `next-call` is the correct answer on every non-preview
  mode, not an error.** The pacing engine originates those calls
  server-side; the endpoint has nothing to hand an agent.

## Symptom index

Find the response you actually get, then work the matching section.

| Symptom                                                                        | Mode it applies to                 | What it means                                                                                                                                                            | Go to                                                                                         |
| ------------------------------------------------------------------------------ | ---------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | --------------------------------------------------------------------------------------------- |
| `GET /next-call` returns `404 NOT_FOUND`                                       | Any                                | The campaign\_id in your query does not match an **active** campaign                                                                                                     | [Claim returns 404 — the campaign isn't active](#claim-returns-404--the-campaign-isnt-active) |
| `GET /next-call` returns `204` with no body                                    | Progressive, predictive, agentless | Correct behavior — those modes dial through the scheduler, not the agent                                                                                                 | [Mode decoder](#mode-decoder--who-dials-and-when)                                             |
| `GET /next-call` returns `200` with `"contact": null`                          | Preview                            | The campaign is active and preview-mode, but no contact is currently eligible to claim                                                                                   | [Preview returns an empty claim](#preview-returns-an-empty-claim)                             |
| `POST /dial` returns `409 CLAIM_NOT_HELD`                                      | Preview                            | The contact you dial is not in the `dialing` (claimed) state — someone else claimed it, the countdown expired, or a prior dial already consumed the claim                | [Claim-not-held — the claim lapsed](#claim-not-held--the-claim-lapsed)                        |
| `POST /dial` returns `409 WRONG_DIALER_MODE`                                   | Non-preview                        | `dial` was called against a progressive / predictive / agentless campaign                                                                                                | [Mode decoder](#mode-decoder--who-dials-and-when)                                             |
| `POST /dial` returns `503 SOFTSWITCH_UNHEALTHY`                                | Preview                            | The failure-rate breaker tripped — the last minutes of originated legs from your workspace failed at the transport layer, so dispatch pauses instead of burning the list | [Softswitch/unhealthy — the breaker tripped](#softswitchunhealthy--the-breaker-tripped)       |
| Campaign auto-flips to `status: 'aborted'`                                     | Predictive (also progressive)      | The rolling 30-day abandonment rate tripped the campaign's `max_abandon_rate`                                                                                            | [Abandonment abort — terminal status](#abandonment-abort--terminal-status)                    |
| Predictive campaign dials but most calls hang up instantly with `amd_detected` | Predictive                         | The AMD application is answering-machine-detecting nearly everything — usually a mis-configured AMD app SID, or a list that genuinely is mostly voicemail                | [Predictive AMD storms](#predictive-amd-storms)                                               |
| Campaign is `active`, list is uploaded, but nothing claims and nothing dials   | Preview                            | Either no agent is polling, or the readiness gate rejects every agent                                                                                                    | [Nothing advances at all](#nothing-advances-at-all)                                           |

## Claim returns 404 — the campaign isn't active

`GET /api/v1/dialer/next-call?campaign_id=<id>` returns
`404 { code: "NOT_FOUND", message: "Active campaign not found" }` in
exactly one case: no row in `dialer_campaigns` matches that id with
`status = 'active'`. The three reasons that hit in practice:

1. **The campaign was never activated.** A campaign created through
   `POST /api/v1/dialer/campaigns` starts in `draft` and dials nothing
   until you `PATCH` it to `active`. This is also the answer to
   "preview claim returns 404 after the last contact" — a campaign
   whose final disposition left it with no remaining work does not
   auto-deactivate, but one you finished and then `PATCH`ed to
   `completed` or `paused` does return 404 to the next poll.
2. **The campaign auto-aborted.** The abandonment ceiling flipped it to
   `aborted` — that status is terminal, and `next-call` treats an
   aborted campaign the same as a missing one. See
   [Abandonment abort](#abandonment-abort--terminal-status).
3. **Wrong id.** A typo or a id from a different workspace. Confirm
   with `GET /api/v1/dialer/campaigns/:id` — if that returns the
   campaign with a non-`active` status, the status is the answer.

The fix is the status, every time. `PATCH {"status": "active"}` for a
paused or draft campaign; create a new campaign for an aborted one (the
`aborted` status cannot be re-activated).

## Preview returns an empty claim

A `200` with `"contact": null` and a resolved `preview_decision_seconds`
means the campaign is active and preview-mode — the eligibility filter
just found nothing. Work the filter's four inputs in order:

1. **Is the list uploaded?** A campaign with no
   `POST /campaigns/:id/lists` upload claims nothing. The upload is a
   separate step from creating the campaign.
2. **Are contacts still `pending`?** `GET /api/v1/dialer/campaigns/:id/stats`
   returns the per-status breakdown. If everything is `connected`,
   `failed`, `dnc`, or `callback_scheduled` and nothing is `pending`,
   the campaign is done — the empty claim is the correct state.
3. **Quiet hours.** A contact whose recipient-local hour falls outside
   the permitted window is deferred with `timezone_blocked` rather than
   failed; it becomes eligible again when the window opens. A bulk list
   of US contacts polled at 11 PM ET legitimately claims nothing. The
   window mechanics and the reason codes the pre-dial gate emits are on
   [Troubleshooting: resolve dialing-window blocked voice calls](/troubleshooting/tcpa-window-blocked-calls).
4. **A stuck claim.** A contact an agent claimed and never dialed or
   dispositioned sits in `dialing`. The campaign's decision countdown
   (`preview_decision_seconds`, defaulting to the platform TTL) re-releases
   it automatically — a past-deadline claim re-enters the eligible pool
   on the next poll. If `contact: null` persists across several minutes
   and the stats show rows stuck in `dialing`, one slow-polling agent is
   holding them; either that agent dials or skips, or the countdown
   releases them.

## Claim-not-held — the claim lapsed

`POST /api/v1/dialer/dial` returns
`409 { code: "CLAIM_NOT_HELD", details: { current_status } }` when the
`contact_id` in the body is not currently in `dialing` state. The claim
is single-owner and time-boxed; three things end it:

* **The countdown expired.** The response from `next-call` carries
  `preview_decision_seconds` and `decision_expires_at` — dial before
  that wall-clock moment or the scheduler re-releases the claim and
  another agent's poll can take the same contact.
* **Another agent already took it.** Two agents polling the same
  preview campaign never receive the same contact concurrently, but a
  skipped or lapsed claim is re-issued — the second agent's claim
  invalidates the first.
* **The contact was already dispositioned.** A completed disposal moves
  the row to its terminal status; dialing it again is a contract
  violation the gate rejects.

The fix is the one in the error message: re-fetch via
`GET /next-call` and dial the newly returned `contact_id`. Do not retry
the same `contact_id` in a loop — it will keep 409ing until you claim a
fresh row. If your agent UI keeps a queue of pre-fetched preview cards,
treat `409 CLAIM_NOT_HELD` as the signal to re-claim rather than
retrying the stale card.

## Softswitch/unhealthy — the breaker tripped

A `503 SOFTSWITCH_UNHEALTHY` from `POST /dial` is the dialer protecting
your list. Before originating, the dialer reads the last minutes of
terminated call attempts from your workspace and trips if the share
that failed at the transport layer exceeds the threshold. Without the
gate, a wholesale-leg outage burns through the list in minutes with
zero connects — and each failed origination counts toward the FCC 3%
abandonment ceiling and your caller-id reputation.

On trip, the contact you claimed is reset back to `pending`, so nothing
is lost. The response `details` object carries `error_rate`,
`total_attempts`, `failed_attempts`, and the window — capture those.
The fix is to wait and re-poll: the gate re-evaluates on every dial,
and the moment real legs start succeeding again, dispatch resumes.
There is no tenant toggle to bypass the breaker, and disabling it is
never the right answer to a transport outage — retrying against a down
wholesale leg only multiplies the abandon-rate damage.

If the 503 persists beyond a few minutes on a campaign whose caller ID
and numbers are unchanged, escalate — the breaker is telling you the
outbound path for your workspace is down.

## Predictive AMD storms

A predictive campaign that dials but where nearly every attempt ends in
`amd_detected` within a second or two of answer is hitting one of these:

* **The AMD application is mis-wired.** Predictive campaigns resolve an
  application SID in three tiers — the campaign's own override, then the
  platform AMD default when `amd_enabled` is true, then the standard
  default. If the AMD-flagged campaign has no AMD application
  resolvable, origination fails closed rather than dialing blind;
  check `amd_enabled` on the campaign and confirm with support that the
  workspace's AMD application is provisioned.
* **The list is genuinely voicemail-heavy.** Answering machines,
  IVRs, and operator intercepts all classify as `amd_detected`. A
  purchased or stale list will swim in them; that's the list, not the
  AMD.
* **Pacing outruns agent supply.** The scheduler over-dials by
  `pacing_ratio` per ready agent. When answered calls find no ready
  agent, they abandon — and answered-then-abandoned calls drive the
  same abandonment metric the ceiling enforces. Drop `pacing_ratio`
  toward 1.0 and re-check the campaign's `ready agent` count against
  actual staffed agents.

The corrective knobs are all campaign-level: `pacing_ratio`,
`max_abandon_rate`, and `amd_enabled` on the campaign, plus the
workspace-level abandon ceiling.

## Abandonment abort — terminal status

The rolling 30-day abandonment rate (`abandon_rate_30d`) feeds the
campaign's abandon gate. When it trips `max_abandon_rate` (default
0.03, clamped at the FCC hard cap of 3%), the campaign flips to
`status: 'aborted'`. That status is **terminal** — you cannot PATCH an
aborted campaign back to active. The error codes page and the launch
guide both call this out; the operational answer is:

1. Read the campaign's `GET /campaigns/:id/stats` — the
   `abandon_rate_30m` value shows whether this was a momentary spike or
   a sustained over-dial.
2. Fix the pacing first: lower `pacing_ratio`, verify ready agents
   actually exist while the campaign runs.
3. Create a **new** campaign with the corrected pacing settings and
   re-upload the remaining list. The aborted campaign stays as the
   audit record.

## Nothing advances at all

The campaign is `active`, the list is uploaded, `next-call` returns
`contact: null`, and predictive/progressive campaigns dial nothing. Work
these in order:

1. **Is anyone polling / ready?** Preview needs an agent polling
   `next-call`; progressive and predictive need agents marked ready in
   the queue the campaign draws from. A predictive campaign with zero
   ready agents paces to zero.
2. **Is every remaining contact deferred?** US-only lists polled outside
   the federal 8 AM–9 PM recipient-local window all sit in
   `timezone_blocked` and claim nothing. Pre-flight the list with the
   quiet-hours preview endpoint before launch — one preview per distinct
   area code covers the list. The full window matrix is on
   [Troubleshooting: resolve dialing-window blocked voice calls](/troubleshooting/tcpa-window-blocked-calls).
3. **Is the campaign's caller ID valid?** A campaign created against a
   caller-id E.164 that has since been released or replaced will fail
   origination on every attempt — which then trips the softswitch
   breaker above, even though the path is up. After any number/port
   change on the numbers side, update the campaign's `caller_id_e164`
   (or its caller-id pool) before resuming.
4. **Check the stats row** (`GET /campaigns/:id/stats`) — the per-status
   breakdown tells you whether contacts are `pending` (never gated),
   `timezone_blocked` (window), `dialing` (stuck claims), or
   `callback_scheduled` (waiting on a future attempt moment).

## When to escalate

Work the symptom section first. Escalate to support with all of the
following — the more of the four, the faster the resolution:

1. **Your tenant / organization ID** — Settings → Organization, or
   `organizationId` from `GET /api/v1/me`.
2. **The campaign ID** and its mode (`preview` / `progressive` /
   `predictive` / `agentless`) and current `status`.
3. **The exact request and response** — for a preview issue, the
   `GET /api/v1/dialer/next-call?campaign_id=<id>` response body (or
   the `POST /dial` body with `campaign_id` and `contact_id`) and the
   full error, including `error.code` and the `details` object.
4. **The error code verbatim** — `CLAIM_NOT_HELD`,
   `SOFTSWITCH_UNHEALTHY`, `WRONG_DIALER_MODE`, `NOT_FOUND`, or the
   TCPA class from the window page. The code routes the escalation to
   the right layer.

For anything compliance-flavored — dialing-window blocks, DNC routing,
recording-consent rejects — keep this page and escalate with the same
four items; the platform will not loosen a federal hard block, but the
gates that fail open are yours to reconfigure.

## See also

* [Launch an outbound dialer campaign](/guides/outbound-dialer-campaign) —
  modes, pacing knobs, the abandonment ceiling, and dispositions.
* [Dialer API](/api-reference/dialer) — the endpoint contracts this page
  references.
* [Troubleshooting: resolve dialing-window blocked voice calls](/troubleshooting/tcpa-window-blocked-calls) —
  the TCPA federal window, state overlays, and the quiet-hours preview
  endpoint.
* [Dialer dispositions](/voice/dialer-dispositions) — the disposition →
  contact-status matrix; a contact stuck in an unexpected status usually
  traces here.
* [Error codes](/reference/error-codes) — the canonical list of the codes
  above.
