Scheduling & Delivery Logic
This guide explains what actually happens when you schedule a batch campaign. At a high level:- You define when you want calls to happen (timezone, daily window, working days).
- Truedy converts your contacts into individual scheduled call slots (
scheduled_at). - A background job then fires calls when those slots become due.
Who this is for
- Teams creating outbound campaigns (sales, renewals, support outreach).
- Developers integrating scheduling into their systems and needing predictable behavior.
Concepts: campaign vs campaign contacts
Campaign (batch call)
The campaign is the configuration:- Which agent to use
- Which contacts to call
- Phone rotation strategy (if multiple outbound numbers)
- Scheduling settings (timezone + time window + caps)
- Current campaign status (
draft,scheduled,active,paused, etc.)
Campaign contacts
Once scheduled, Truedy creates one row per contact, often called campaign contacts. Each campaign contact receives its own:status(pending/scheduled/completed/failed/etc.)scheduled_attimestamp (the time Truedy will attempt to place the call)
Input parameters (what you control)
From the Public APIPOST /batch-calls, you can set:
schedule_typeimmediate(default): campaign may move forward right awayscheduled: you provide a start datetime and daily rules
scheduled_at(required whenschedule_type = scheduled)- ISO datetime indicating when the schedule window begins (used with
timezone)
- ISO datetime indicating when the schedule window begins (used with
timezone(defaultUTC)- IANA timezone (e.g.
America/New_York)
- IANA timezone (e.g.
start_timeandend_time- Daily window start/end (e.g.
09:00to18:00)
- Daily window start/end (e.g.
working_days- Allowed days of week (1=Mon … 7=Sun)
max_calls_per_day- Daily cap enforced by the scheduler
max_concurrent_calls- Upper bound on how many calls can be in-flight at once
Step-by-step: from draft to scheduled
You can schedule a campaign in two common ways:Option A: Provide scheduling on creation
If you create withschedule_type: "scheduled" and include scheduled_at, the campaign can be considered scheduled per the request.
Option B: Create draft, then call the schedule endpoint
If you create the campaign asdraft, you can explicitly schedule it later:
- Create the batch call
- Add contacts to the draft
- Call
POST /batch-calls/{batch_call_id}/schedule
What the scheduler does (the delivery algorithm)
When you schedule a campaign, the scheduling engine:- Validates prerequisites:
- The batch has an agent and outbound phone numbers
- There is at least one pending contact
- Prepares call payloads:
- Applies phone rotation strategy (e.g. sequential/random/round robin)
- Distributes contacts across days:
- Uses
timezone,working_days, and dailystart_time/end_time - Enforces
max_calls_per_day
- Uses
- Assigns each contact a unique
scheduled_attimestamp:- These are the times each call becomes due
- Enqueues delivery:
- A background job later fires due contacts
Concurrency: what max_concurrent_calls really affects
max_concurrent_calls does not change the scheduled_at planning step.
Instead, it affects how many scheduled calls the background job can launch at the same time when multiple contacts become due.
Practical guidance:
- If calls are failing due to provider saturation, reduce
max_concurrent_calls. - If your campaign is too slow, increase gradually (and ensure your integration is not rate-limited).
Status gating: when delivery is allowed
The scheduler only fires for campaigns in the correct state. In practice:activeandscheduledcampaigns can deliver calls.pausedcampaigns should not deliver new calls (future scheduled contacts are held).
Updating schedule settings (safe rescheduling)
If you PATCH scheduling parameters while a campaign is in a compatible state:scheduled_atstart_time/end_timemax_calls_per_dayworking_days
Concrete cURL examples
1) Schedule batch call (create + schedule)
Create a scheduled campaign draft:2) Verify delivery planning (inspect scheduled contacts)
3) Adjust schedule later (redistribute future contacts)
Troubleshooting
“Nothing is being delivered”
Common checks:- Is the campaign in
scheduledoractivestate (notpaused)? - Does today fall inside
working_days? - Is the current local time (per
timezone) insidestart_time/end_time? - Did scheduling validate successfully (agent synced, outbound numbers assigned, contacts exist)?
“Some contacts never change status”
Use the batch contacts endpoint:- List contacts filtered by
status=scheduledto confirm they were planned. - Then filter by
status=failedto identify provider/conversation failures.
Next steps
- If you need runtime control: Pause/Resume & Edit Campaigns
- If you need outcomes: Campaign Analytics & Reporting

