Skip to main content

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_at timestamp (the time Truedy will attempt to place the call)
All analytics are built from these campaign contact outcomes.

Input parameters (what you control)

From the Public API POST /batch-calls, you can set:
  • schedule_type
    • immediate (default): campaign may move forward right away
    • scheduled: you provide a start datetime and daily rules
  • scheduled_at (required when schedule_type = scheduled)
    • ISO datetime indicating when the schedule window begins (used with timezone)
  • timezone (default UTC)
    • IANA timezone (e.g. America/New_York)
  • start_time and end_time
    • Daily window start/end (e.g. 09:00 to 18:00)
  • 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
For full field definitions, see:

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 with schedule_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 as draft, you can explicitly schedule it later:
  1. Create the batch call
  2. Add contacts to the draft
  3. Call POST /batch-calls/{batch_call_id}/schedule
This maps to the API docs:

What the scheduler does (the delivery algorithm)

When you schedule a campaign, the scheduling engine:
  1. Validates prerequisites:
    • The batch has an agent and outbound phone numbers
    • There is at least one pending contact
  2. Prepares call payloads:
    • Applies phone rotation strategy (e.g. sequential/random/round robin)
  3. Distributes contacts across days:
    • Uses timezone, working_days, and daily start_time/end_time
    • Enforces max_calls_per_day
  4. Assigns each contact a unique scheduled_at timestamp:
    • These are the times each call becomes due
  5. Enqueues delivery:
    • A background job later fires due contacts
This behavior is described directly in:

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:
  • active and scheduled campaigns can deliver calls.
  • paused campaigns should not deliver new calls (future scheduled contacts are held).
Pause/resume behavior is documented in:

Updating schedule settings (safe rescheduling)

If you PATCH scheduling parameters while a campaign is in a compatible state:
  • scheduled_at
  • start_time / end_time
  • max_calls_per_day
  • working_days
Truedy will redistribute contacts across the new schedule. See:

Concrete cURL examples

1) Schedule batch call (create + schedule)

Create a scheduled campaign draft:
curl -X POST "https://api.truedy.ai/api/public/v1/batch-calls" \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -H "X-Idempotency-Key: 33333333-3333-3333-3333-333333333333" \
  -d '{
    "name": "Delivery Logic Example",
    "agent_id": "1f4baf16-1540-4d91-9696-7f34b2f2cb77",
    "contact_source": "folder",
    "contact_folder_id": "6f4af8be-0a96-49b0-ac2a-a359f46cc966",
    "schedule_type": "scheduled",
    "scheduled_at": "2026-03-20T14:30:00Z",
    "timezone": "America/New_York",
    "start_time": "10:00",
    "end_time": "17:00",
    "working_days": [1,2,3,4,5],
    "max_concurrent_calls": 8,
    "max_calls_per_day": 120
  }'

2) Verify delivery planning (inspect scheduled contacts)

curl "https://api.truedy.ai/api/public/v1/batch-calls/BATCH_CALL_ID/contacts?status=scheduled&limit=50&offset=0" \
  -H "Authorization: Bearer YOUR_API_KEY"

3) Adjust schedule later (redistribute future contacts)

curl -X PATCH "https://api.truedy.ai/api/public/v1/batch-calls/BATCH_CALL_ID" \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "start_time": "09:30",
    "end_time": "16:30",
    "max_calls_per_day": 80
  }'

Troubleshooting

“Nothing is being delivered”

Common checks:
  • Is the campaign in scheduled or active state (not paused)?
  • Does today fall inside working_days?
  • Is the current local time (per timezone) inside start_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=scheduled to confirm they were planned.
  • Then filter by status=failed to identify provider/conversation failures.

Next steps