Skip to main content
Why didn’t my upload go out instantly? Because your platform would have rejected it if it had. Five9 enforces hard per-Domain call limits — across a minute, an hour, and a day, all at once — and GetDialed paces outbound work against those limits instead of firing calls until the provider starts throwing errors. Queued work waits rather than failing: a large upload is delivered as fast as the Domain’s budget allows and never faster.

How pacing works

Every outbound call to a Domain draws from that Domain’s rate buckets. Each bucket carries the provider’s raw caps for three windows — 60 seconds, one hour, and one day — reduced by your configured safety margin. All three windows are enforced simultaneously: a call is sent only when it fits inside the minute, the hour, and the day budget. The budget is debited before a call is sent, never reconciled after the fact. That ordering is the guarantee: the paced dispatcher cannot exceed the provider’s limits by design, because a call with no budget behind it is simply not sent yet. Work that does not fit the current window sits in the queue and goes out when the window rolls over. Two consequences worth internalizing:
  • A big upload is delivered in paced slices. One million records is around twenty upload calls, and with the default Upload bucket that is roughly a minute of budget — but a busy Domain, a tightened margin, or competing work can stretch it. The batch reports honest progress the whole way.
  • Synchronous calls fail fast instead of queueing. When you are waiting on an HTTP response — testing a connection, refreshing a Domain’s limits — an exhausted budget returns 429 with a Retry-After header rather than silently holding your request. Nothing is sent, nothing is queued; retry after the advertised wait.

When the provider says slow down

If Five9 returns a rate-limit response anyway (another system may be spending the same Domain’s budget), GetDialed pauses only the affected operation class — the one rate bucket that was throttled — for the remainder of that window, then resumes on its own. Uploads backing off never block report reads, and vice versa. These automatic backoffs appear in the pause listing like every other hold, with a machine-readable cause naming the provider fault that opened them. They release themselves at the window boundary and cannot be lifted early — resuming into a limit the provider just enforced would only trip it again.

Pause scopes

Sometimes you want dispatch held: a provider maintenance window, a campaign under review, a batch uploaded to the wrong list. Four admin-controlled scopes exist, from widest to narrowest: Only the batch scope touches a batch’s status. A global, Domain, or lane hold does not rewrite the batches it affects — those holds are visible on the pause listing and the Domain surface instead, because the batches themselves are not individually paused; their Domain is. Every pause — yours or the system’s — is an auditable record: who opened it, when, why, its scope and target, and (once resumed) who released it and when. Listing the records answers “what is holding dispatch right now?” in one call.

Pause is not cancel

Pausing deletes nothing and cancels nothing. Work already dispatched stays dispatched; work not yet dispatched stays queued, exactly where it was. Resume releases the hold and dispatch continues from precisely where it stopped — nothing is re-sent, so pausing and resuming can never contact the same person twice. A pause can carry an optional duration_seconds (1 second up to one week), which schedules an automatic resume. A scheduled resume can be pushed further out before it fires — forward only; shortening a hold is an explicit resume. An open-ended pause simply holds until someone resumes it. The paused batch status is not terminal. It is a state a batch returns from: resuming restores the exact status the batch held before the pause — a batch paused while queued goes back to queued, never promoted to running.

What needs_reconcile means

Uploads are sent exactly once — never blindly retried, because retrying an upload without knowing whether the first attempt landed risks contacting the same person twice. That honesty has a corner case: the call went out, and no confirmation came back. A job in that situation is parked as needs_reconcile: we sent the upload but did not receive a confirmation, so we are not guessing. These rows are held, not retried. The status is not terminal — it is an explicit “outcome unknown” that will be resolved against the provider’s own records in a later release, and the rest of the batch keeps processing normally in the meantime. If you see needs_reconcile on a few rows of a large batch, nothing is stuck: the ambiguous slice is quarantined and everything else continues.

Batched delivery waits honestly

A flow step using batched delivery hands its records to the paced dispatcher and waits for the real outcome. On a busy or paused Domain that wait can be long — hours, if the budget demands it — and that is by design: the step reports the provider’s actual result (or an honest non-terminal status such as needs_reconcile), never a fabricated timeout failure for work the provider may still complete.

Next steps

Pause & resume API

Every pause, resume, listing, and extension endpoint, with bounds and error cases.

Platform tenancy

The Domain record whose rate buckets and margins set the budget.

Batches, jobs, and executions

Every status in the chain, including paused and needs_reconcile.

Bulk ingestion

Stage millions of records ahead of time; dispatch is paced when you trigger.