Skip to main content

Scaling & Concurrency

When you scale from “a few calls” to “lots of calls”, four things matter:
  • Your scheduling limits (campaign caps)
  • Concurrency controls (how many calls happen at once)
  • API rate limits (429 responses)
  • Idempotency & deduplication (safe retries for API + webhooks)

Who this is for

  • Teams launching outbound campaigns or high-volume automations.
  • Developers designing a reliable integration (no duplicate side effects).

Understand the two layers of limits

1) Campaign-level limits (batch engine pacing)

Campaign requests include:
  • max_concurrent_calls: how many calls can be in-flight at once for that campaign
  • max_calls_per_day: a daily cap for how many calls the campaign will place
  • Schedule parameters that determine when contacts are eligible:
    • timezone
    • working_days
    • start_time / end_time
These limits affect how many calls the background scheduler tries to launch.

2) API-level limits (your integration throughput)

Even if a campaign schedules successfully, your integration still might hit rate limits if you poll too aggressively or trigger too many requests at once.
  • On 429, handle retries using backoff.
  • Use idempotency keys for create/write endpoints so retries do not create duplicates.
See:

Configure concurrency safely (batch campaign example)

Here’s an example payload that sets both pacing controls:
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: 22222222-3333-4444-5555-666666666666" \
  -d '{
    "name": "Scaling Test Campaign",
    "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
  }'

Pause/Resume to adjust without breaking history

If you need to reduce load:
  • Use Pause to stop future scheduled calls from firing.
  • Use Resume to continue when things look good again.
This is critical for reliable operations: you avoid “half-processed” states where already-completed calls are affected. For the exact semantics, see the Public API:

Reliable retries: API and webhooks

API writes: use X-Idempotency-Key

For create/update/write operations, always send:
  • X-Idempotency-Key: <uuid>
This prevents duplicate campaign/call records when your request is retried.

Webhook receivers: dedupe by event ID

Your webhook endpoint may receive duplicates (for example after retries). Implement idempotency by:
  • Persisting the webhook id / event_id you’ve processed.
  • Ignoring duplicates.
See:

Troubleshooting scaling problems

If you see unexpected behavior, check:
  • Are you sending a unique X-Idempotency-Key on every retry?
  • Are you respecting rate limits (429)?
  • Are you increasing max_concurrent_calls gradually?
  • Are you using webhooks (push) instead of polling too frequently?

Next steps