> This page is for Voice AI Platform.

> For clean Markdown of any page, append .md to the page URL.
> For a complete documentation index, see https://docs.hams.ai/llms.txt.
> For AI client integration (Claude Code, Cursor, etc.), connect to the MCP server at https://docs.hams.ai/_mcp/server.

# Outbound dialer

> How a published batch becomes calls, what each lead status means, and the settings operators can tune.

The dialer has no endpoints of its own. It watches the batches you create through the
[Outbound batches](/platform/outbound-batches) API and works through their leads, and everything it
does is visible as lead statuses and call attempts on those batches. This page explains what happens
between `publish` and `COMPLETED`.

## Two processes

**The dial cycle** runs every few seconds. Each pass claims pending leads from every active batch,
up to the batch's `fetch_limit`, marks them `DIALING`, spreads them across the available Asterisk
servers and asks each server to originate the calls. Originates are sent concurrently, with a small
pacing gap between them, so a batch of a few hundred leads gets going within a minute. Exactly one
dial cycle runs at a time across the whole platform.

**The AMI listener** is a single always-on process holding a connection to every Asterisk server.
When a call is answered, goes unanswered, hits a busy line or fails, Asterisk reports it and the
listener writes the outcome to the lead. Without the listener, dialed leads would stay `DIALING`
forever and no batch would ever complete.

When a lead is dialed, the voice worker that answers the call loads the batch's AI agent and the
lead's `dynamic_variables`, so the agent knows who it is talking to.

## Lead lifecycle

```
PENDING ──▶ DIALING ──▶ ANSWERED
                   ├──▶ NO_ANSWER
                   ├──▶ BUSY
                   └──▶ FAILED
```

| Status      | Meaning                                                                                  |
| ----------- | ---------------------------------------------------------------------------------------- |
| `PENDING`   | Not dialed yet; the dial cycle may claim it                                              |
| `DIALING`   | An originate has been sent and the call is in flight                                     |
| `ANSWERED`  | The remote party answered; the agent handled the call                                    |
| `NO_ANSWER` | Nobody answered before the timeout                                                       |
| `BUSY`      | The line was busy                                                                        |
| `FAILED`    | The originate was rejected, the number could not be reached, or a network error occurred |

`ANSWERED` leads also carry an `end_reason`: `USER` when the remote party hung up, `SYSTEM` when
the agent or our side ended the call. The current dialer makes one attempt per lead: a lead that ends
in `NO_ANSWER`, `BUSY` or `FAILED` stays there.

Each attempt is recorded separately as a call attempt with the server it was sent to, the trunk and
extension used, the dialed number, the caller id, timings and one of these statuses:
`originate_requested`, `originate_sent`, `originate_failed`, `IN_CALL`, `ANSWERED`, `NOT_ANSWERED`,
`REJECTED_SRV`, `REJECTED_CLIENT`, `BUSY`.

## Batch lifecycle

A batch is only dialed while it is `ACTIVE`. Stopping a batch (`POST …/stop`) sets it to `STOPPED`:
the dial cycle skips it from the next pass, but leads already `DIALING` finish and get their
outcome. Adding leads to a stopped or completed batch reopens it.

Completion is counted, not polled: every terminal outcome increments the batch's `completed_leads`,
and when it reaches `total_leads` the batch flips to `COMPLETED`.

> **Note**
>
> The dialer does not gate calls on the time of day. If you need calling hours, publish the batch when
> the window opens and stop it when it closes, or schedule the batch with `scheduled_date`.

## Operator settings

These are environment settings on the platform, not per-batch fields. Defaults are shown.

| Setting                                | Default                     | Effect                                                        |
| -------------------------------------- | --------------------------- | ------------------------------------------------------------- |
| `DIALER_ENABLED`                       | `true`                      | Turns the dial cycle on or off                                |
| `DIALER_CYCLE_SECONDS`                 | `10`                        | Pause between passes                                          |
| `DIALER_RUN_SECONDS`                   | `30`                        | How long one locked run keeps looping before it is relaunched |
| `DIALER_ORIGINATE_CONCURRENCY`         | `8`                         | Originates in flight at once                                  |
| `DIALER_ORIGINATE_INTERVAL_MS`         | `80`                        | Pacing gap between originates                                 |
| `DIALER_FETCH_TO_LAUNCH_DELAY_SECONDS` | `2`                         | Delay between claiming leads and launching their calls        |
| `DIALER_LAUNCH_WINDOW_SECONDS`         | `5`                         | Window in which a pass's originates are launched              |
| `AMI_PORT`                             | `5038`                      | Asterisk Manager Interface port                               |
| `AMI_USERNAME`                         | `dialeroutbound`            | AMI user                                                      |
| `AMI_PASSWORD`                         | —                           | AMI password                                                  |
| `AMI_TIMEOUT`                          | `5`                         | Seconds to wait for an AMI response                           |
| `AMI_ORIGINATE_CHANNEL_TEMPLATE`       | `Local/{number}@outbound/n` | Channel used to place the call                                |
| `AMI_ORIGINATE_CONTEXT`                | `pipecat`                   | Dialplan context the answered call is sent to                 |
| `AMI_ORIGINATE_EXTEN`                  | `s`                         | Dialplan extension                                            |
| `AMI_ORIGINATE_PRIORITY`               | `1`                         | Dialplan priority                                             |
| `AMI_LISTENER_RECONNECT_SECONDS`       | `5`                         | Wait before the listener reconnects to a dropped server       |
| `AMI_LISTENER_REAP_TIMEOUT_SECONDS`    | `300`                       | Age after which an attempt with no outcome is reaped          |

> **Warning**
>
> Keep the `/n` suffix on the channel template. Without it Asterisk optimises the local channel away
> and call recording stops working.