Concurrency
Two limits bound how many calls run at once.| Limit | Scope | Default | Maximum |
|---|---|---|---|
concurrency_limit | Per organization | 10 | 10000 |
| Global concurrency limit | Across all organizations | 50 | — |
/campaign/concurrency-settings endpoint. If an organization has never set one, it falls back to 10.
campaigns:read, campaigns:manage, concurrency:read, or concurrency:manage. Updating requires campaigns:manage or concurrency:manage.
Active calls for an organization counts contacts in either the locked or in_progress status. An organization is at capacity when its active count reaches its concurrency_limit.
How slots are allocated
On each cycle the dialer computes how many global slots are free (global limit − total active calls across all orgs). If none are free, it waits for the next cycle. Free slots are then distributed proportionally to each organization’s concurrency_limit, but never more than the room that organization has left (concurrency_limit − active calls). Whole slots are handed out first by proportional floor, then any leftover slots go to the organizations with the largest fractional shares.
The per-org limit caps your simultaneous calls, but the shared global limit means the exact number running at any instant also depends on demand from other organizations.
The dialer loop
The dialer runs as a continuous worker, polling roughly once per second by default. Each cycle does the following.Sweep stale locks
Contacts stuck in
locked longer than the threshold are returned to pending so they can be retried.Find eligible timezones
For each active campaign configuration, the dialer evaluates the calling windows and works out which timezones are currently inside their window. Contacts not attached to a campaign bypass timezone filtering and are always eligible.
Allocate slots
It reads per-org concurrency stats, computes free global slots, and allocates them proportionally (see above).
Fetch contacts
It pulls due contacts that fit the allocation and the eligible timezones, ordered by priority. A contact is due when it is
pending and any pending retry time has passed.A single attempt
Each attempt selects which phone number to call based on how many attempts the contact has already had, places the call, and waits for it to complete.Phone number selection
A contact can carry several phone numbers in order. Each number is tried up tomax_attempts_per_phone_number times (default 2) before the dialer moves on to the next number in the list. When every number has used all of its attempts, the contact is exhausted.
Per-call timeout
After the call is initiated, the attempt waits up to 30 minutes for a completion signal. If no signal arrives in that window, the attempt is recorded as atimeout.
Attempt outcomes
| Outcome | Meaning |
|---|---|
completed | The call finished and reported success. |
failed | The call ended without reporting success (and did not time out). |
timeout | No completion signal arrived within the 30-minute window. |
Retries and resolution
What happens after an attempt depends on whether it completed and whether any attempts remain.| Result of attempt | Next state of contact |
|---|---|
completed | Contact marked completed — no further calls. |
| Not completed, attempts remain | Retry scheduled about an hour later (RETRY_DELAY_MINUTES = 60). |
| Not completed, no attempts remain | Contact marked exhausted. |
retry_after time roughly one hour ahead; the dialer will not pick the contact up again until that time has passed. When retried, the attempt count advances, which is what eventually moves selection to the next phone number and then to exhaustion.
“Attempts remain” means the next attempt index still maps to a phone number in the contact’s list, given
max_attempts_per_phone_number. A contact with no phone numbers at all is exhausted immediately.Where to go next
Campaigns overview
How campaigns, contacts, and configurations fit together.
Results and analytics
Inspect attempts, dispositions, and call outcomes.

