Scheduling & Retries
Control when calls go out, how concurrency is shared, and what happens on no-answer.
Campaigns have four scheduling levers: when to start, what hours to dial, how many calls in parallel, and how to retry.
When to start
| Mode | Behavior |
|---|---|
start immediately | Campaign goes to running right after you POST /start. First calls go out at the next 15-second dialer tick. |
scheduledStartAt | Campaign stays in scheduled until that timestamp; then auto-transitions to running. |
{
"scheduledStartAt": "2026-05-08T09:00:00+05:30"
}Dialing window (TCPA / TRAI compliance)
Most jurisdictions restrict when you can call. osmTalk enforces a per-campaign dialing window in the recipient's timezone — calls outside the window are skipped and resumed when the window reopens.
{
"schedule": {
"timezone": "Asia/Kolkata",
"windowStart": "10:00",
"windowEnd": "19:00",
"weekdays": [1, 2, 3, 4, 5]
}
}| Field | Purpose | Default |
|---|---|---|
timezone | IANA zone (e.g. Asia/Kolkata, America/New_York) | Asia/Kolkata |
windowStart / windowEnd | 24-hour HH:MM strings | 09:00 / 19:00 |
weekdays | Array of 0-6 (Sun=0) — days when dialing is allowed | [0,1,2,3,4,5,6] |
The dialer evaluates this on every tick. Pause a campaign during banned hours costs nothing — the campaign just sits idle and resumes automatically.
US TCPA quick rule
For US recipients, the safe window is 8 AM – 9 PM local, no calls on federal holidays. Use:
{ "schedule": { "timezone": "America/New_York", "windowStart": "08:00", "windowEnd": "20:30", "weekdays": [1,2,3,4,5] } }(Conservative — caps at 8:30 PM to avoid edge cases.)
India TRAI
Outbound commercial calls in India are restricted to 09:00 – 21:00 local. Default values are already safe.
Concurrency
| Setting | Scope | Caps at |
|---|---|---|
maxConcurrent | Per-campaign | Org cap (default 15) |
MAX_CONCURRENT_CALLS_PER_ORG env | Per-org | Global cap |
MAX_CONCURRENT_CALLS env | Platform-wide | Deepgram PAYG limit (45) |
Example: org cap = 15, and you have two campaigns running each with maxConcurrent: 10. The dialer respects both — you'll see up to 10 calls per campaign and up to 15 in total org-wide.
If you've configured an external dialer at the carrier level (e.g., a predictive dialer queue), set maxConcurrent: 1 per campaign and let the carrier handle pacing.
Retry policy
When a call ends in no_answer, busy, or failed, the lead can be re-dialed:
{
"retryPolicy": {
"maxAttempts": 3,
"backoffMinutes": 60,
"retryOn": ["no_answer", "busy"]
}
}| Field | Purpose | Default |
|---|---|---|
maxAttempts | Hard cap including the first attempt | 3 |
backoffMinutes | Wait between attempts | 60 |
retryOn | Which outcomes trigger a retry | ["no_answer", "busy"] |
Possible retryOn values: no_answer, busy, failed, voicemail. Most teams exclude voicemail because the bot already left a message on the first attempt.
When the lead exhausts maxAttempts, its status is set to failed (terminal).
Recommended starting policies
B2B cold outreach:
{ "maxAttempts": 4, "backoffMinutes": 120, "retryOn": ["no_answer", "busy"] }Renewal reminders:
{ "maxAttempts": 2, "backoffMinutes": 240, "retryOn": ["no_answer"] }Aggressive recovery (use sparingly):
{ "maxAttempts": 6, "backoffMinutes": 30, "retryOn": ["no_answer", "busy", "failed"] }Manual control
You can override the scheduler at any time:
# Pause — stops new dials, lets in-flight calls finish
curl -X POST /api/campaigns/{id}/pause
# Resume — accepts new dials at the next tick
curl -X POST /api/campaigns/{id}/resume
# Stop — forces completed; any in-flight calls finish but no new dials
curl -X POST /api/campaigns/{id}/stopManual pause + resume respects the dialing window when resumed. There's no way to override the window without editing the campaign.