Scheduling and concurrency

A campaign that fires 10,000 calls in 30 seconds gets you blocklisted by your carrier. Saaya schedules dispatch across calling windows, throttles by region, and respects per-number concurrency caps so you stay in good standing.

Time-of-day windows

Every campaign declares a window in IANA timezone strings, `weekdays-09-18-IST`, `weekends-12-17-PT`, or a custom rule. Saaya pauses dispatch outside the window and resumes when it reopens, even across multi-day campaigns.

schedule.ts
await saaya.campaigns.update(campaign.id, {
  schedule: {
    window:    { tz: "Asia/Kolkata", days: ["mon","tue","wed","thu","fri"], from: "09:00", to: "18:00" },
    perNumberConcurrency: 30,
    rampUpSeconds:        60,
  },
});

Region-aware throttling

Saaya throttles dispatch by destination country. India and the US tolerate higher concurrency; some EU markets require gentler ramp-up to avoid spam-flagging. Sane defaults ship out of the box; override per-campaign when you know your carrier's appetite.

Queue limits

  • Per-number concurrency: max simultaneous calls on a single sender (default 30).
  • Org-wide concurrency: capped on your plan (Business: 500, Scale: 5000).
  • Carrier ramp-up: starts at 5 cps, doubles every 30s until target.
  • Daily caps: optional per-agent or per-number throttle to spread load across days.

Pausing and resuming

A live campaign can be paused with `campaigns.pause`. In-flight calls finish; pending rows stay in the queue. `campaigns.resume` picks up exactly where it left off, Saaya tracks the cursor so retries are deterministic.

Watch the live campaign view

The dashboard's campaign live view shows dispatch rate, answer rate, average duration, and current concurrency in real time. If something looks off, pause first and investigate, never let a bad campaign run dry.
Was this page helpful?