POST
/
v1
/
orgs
/
{org_id}
/
workspaces
/
{workspace_id}
/
campaigns
Create Campaign
curl --request POST \
  --url https://apps.sarvam.ai/api/scheduling/v1/orgs/{org_id}/workspaces/{workspace_id}/campaigns \
  --header 'Content-Type: application/json' \
  --header 'X-API-Key: <api-key>' \
  --data '
{
  "name": "Q1 Payment Reminders",
  "description": "Outbound reminder calls for Q1 overdue accounts",
  "app_config": {
    "app_id": "agent-abc123",
    "app_version": 1,
    "app_type": "agent",
    "attempts_per_second": 2,
    "connection_configs": [
      {
        "connection_id": "conn-xyz",
        "phone_numbers": [
          "+918041234567"
        ],
        "weight": 1
      }
    ],
    "retry_config": {
      "max_retries": 3,
      "retry_interval_minutes": 30,
      "retry_on": {
        "busy": {
          "enabled": true
        },
        "no_answer": {
          "enabled": true
        },
        "short_duration": {
          "enabled": true,
          "threshold_seconds": 30
        }
      }
    },
    "webhook_config": {
      "url": "https://your-server.com/webhook",
      "metadata": {
        "team": "collections"
      }
    }
  },
  "start_timestamp": "2026-04-01T09:00:00Z",
  "end_timestamp": "2026-04-15T18:00:00Z",
  "allowed_schedule": {
    "timezone": "Asia/Kolkata",
    "allowed_start_time": "09:00",
    "allowed_end_time": "18:00",
    "allowed_days": [
      "Monday",
      "Tuesday",
      "Wednesday",
      "Thursday",
      "Friday"
    ]
  }
}
'
{
  "name": "<string>",
  "campaign_id": "<string>",
  "status": "ended",
  "app_id": "<string>",
  "created_by": "<string>",
  "created_at": "2023-11-07T05:31:56Z",
  "updated_at": "2023-11-07T05:31:56Z",
  "description": "<string>",
  "app_type": "agent",
  "app_version": 123,
  "updated_by": "<string>"
}

Overview

A campaign ties an agent to a schedule, rate, and retry policy — defining who to contact, when, and how fast. The campaign is created in scheduled status and activates automatically when start_timestamp is reached. Cohorts can be uploaded at any point — before the campaign starts, while it’s active, or after a pause. Each new cohort is processed independently and queued for calling. Start with a small test cohort to validate your agent’s performance, then scale up by uploading larger batches.

Key constraints

  • start_timestamp must be at least 120 seconds from now and no more than 7 days from now
  • end_timestamp must be at least 120 seconds after start_timestamp and no more than 30 days after it
  • allowed_schedule defines the business-hours window (timezone, days, time range) within which calls are placed — dials only happen inside this window

Typical flow

  1. Create a campaign with agent config, schedule, and retry policy
  2. Upload one or more cohorts — each is a CSV of users + transformation config
  3. System processes and dispatches calls at the configured rate
  4. Retry engine handles failures automatically
  5. Upload additional cohorts at any time while the campaign is running
  6. Campaign ends when the time window expires or you cancel it

Call Rate

attempts_per_second is the rate at which the system places outbound dials. It is a dial rate, not an answer rate — every outbound dial counts as one attempt, regardless of whether it connects. Range: 0.1500

Attempts

  • Each initial outbound dial = 1 attempt
  • Each retry = 1 additional attempt
  • Busy, no-answer, short-duration, and connected calls all count equally
A user with max_retries: 3 can generate up to 4 attempts total (1 initial + 3 retries).

Capacity planning

Calls are only placed within your allowed_schedule window. Use this formula:
Total attempts = attempts_per_second × 3600 × calling_hours_per_day × campaign_days
This is the theoretical maximum. Any time the campaign spends paused, outside the allowed schedule, or waiting between retries reduces the actual number of attempts placed.
Quick reference:
Rate (per sec)Per minutePer hour8-hour day
0.5301,80014,400
1603,60028,800
21207,20057,600
530018,000144,000
1060036,000288,000

Retry conditions

Retries are triggered based on how the previous call ended. Configure which outcomes should be retried under retry_config.retry_on:
ConditionWhen it triggers
busyCallee line was busy
no_answerCall rang but was not answered
short_durationCall connected but ended sooner than threshold_seconds
failedCall failed to connect (e.g., number unreachable)
provider_errorTelephony provider returned an error
internal_errorInternal system error
short_duration in detail A call is considered short-duration when the user answers but hangs up quickly — before the conversation has a meaningful chance to happen. Common causes: the user didn’t realize it was a call, accidentally answered, or the call dropped immediately after connecting. threshold_seconds sets the cutoff. Any call that connects and lasts less than this value is treated as incomplete and queued for a retry.
{
  "short_duration": { "enabled": true, "threshold_seconds": 30 }
}
With this config, a call that lasted 12 seconds would be retried. A call that lasted 45 seconds would not. Range: 11200 seconds.
Set threshold_seconds to roughly the minimum time your agent needs to deliver its opening message. If the intro takes ~20 seconds, a value of 2530 is a reasonable threshold.

Retry budget

Your effective attempt budget = cohort_size × (1 + max_retries).
Cohort sizemax_retriesMax total attempts
1,00001,000
1,00034,000
10,000340,000
If attempts_per_second × window is less than this, some users may not complete all retries before the campaign ends.

Load balancing

If you configure multiple connection_configs, traffic is split proportionally by weight. With weights 3 and 1, 75% of dials go through the first connection, 25% through the second. Phone numbers within each connection are used equally.
{
  "connection_configs": [
    { "connection_id": "conn-a", "phone_numbers": ["+918041234567"], "weight": 3 },
    { "connection_id": "conn-b", "phone_numbers": ["+918049876543"], "weight": 1 }
  ]
}

Choosing the right rate

SituationGuidance
New campaign, untested agentStart low — validate quality before scaling
Large cohort, short windowRaise the rate to cover all users within the window
Rate too lowCampaign runs out of time before reaching all users
Rate too highReduce if you see telephony errors or degraded quality
Start low, then scale up. Pause the campaign, update app_config.attempts_per_second, and resume — no other fields need to change.
Answer rates vary by audience and time of day. A 40–60% connect rate is typical — not every dial will become a conversation. Factor this into your cohort size and rate planning.

Example request

{
  "name": "Q1 Payment Reminders",
  "description": "Outbound reminder calls for Q1 overdue accounts",
  "app_config": {
    "app_id": "agent-abc123",
    "app_version": 1,
    "app_type": "agent",
    "attempts_per_second": 2,
    "connection_configs": [
      {
        "connection_id": "conn-xyz",
        "phone_numbers": ["+918041234567"],
        "weight": 1
      }
    ],
    "retry_config": {
      "max_retries": 3,
      "retry_interval_minutes": 30,
      "retry_on": {
        "busy": { "enabled": true },
        "no_answer": { "enabled": true },
        "short_duration": { "enabled": true, "threshold_seconds": 30 }
      }
    },
    "webhook_config": {
      "url": "https://your-server.com/webhook",
      "metadata": { "team": "collections" }
    }
  },
  "start_timestamp": "2026-04-01T09:00:00Z",
  "end_timestamp": "2026-04-15T18:00:00Z",
  "allowed_schedule": {
    "timezone": "Asia/Kolkata",
    "allowed_start_time": "09:00",
    "allowed_end_time": "18:00",
    "allowed_days": ["Monday", "Tuesday", "Wednesday", "Thursday", "Friday"]
  }
}

Key fields

FieldRange / Notes
app_config.attempts_per_second0.1500
app_config.retry_config.max_retries020
app_config.retry_config.retry_interval_minutesMin 5 min; accepts a single integer or an array for variable intervals
app_config.connection_configs[].weight1100; default 1
start_timestamp120 seconds – 7 days from now
end_timestampAt least 120 seconds after start; max 30 days from start

End-to-end flow

  1. Create the campaignPOST /campaigns
    Returns campaign_id with status: scheduled.
  2. Upload a cohortPOST /campaigns/{id}/cohorts/upload
    Returns cohort_id with status: processing.
  3. Poll until processing completesGET /campaigns/{id}/cohorts/{cohort_id}
    Wait for status: completed or failed.
  4. Check for rejected records — if result.rejected_records > 0, download and review:
    GET /campaigns/{id}/cohorts/{cohort_id}/files?file_type=rejected_records
  5. Campaign activates automatically at start_timestamp
    Status transitions: scheduledactive.
  6. Monitor and control as needed:
    GET /campaigns/{id} · PUT /campaigns/{id}/status (pause / resume / cancel)
Check for rejected records right after cohort processing completes. Rejected users will never be called — catching them early lets you fix data issues and re-upload before the campaign goes live.

Next: Upload a Cohort

After creating a campaign, upload a CSV of users to start placing calls.

Authorizations

X-API-Key
string
header
required

Path Parameters

org_id
string
required
workspace_id
string
required

Body

application/json

Request body for creating a new campaign. Ties an agent to a schedule, rate, and retry policy.

name
string
required
Example:

"Q1 Payment Reminders"

app_config
Agent Config · object
required

Agent configuration for the campaign

start_timestamp
string<date-time>
required

Campaign start time (ISO 8601)

Example:

"2026-04-01T09:00:00Z"

end_timestamp
string<date-time>
required

Campaign end time (ISO 8601)

Example:

"2026-04-15T18:00:00Z"

allowed_schedule
AllowedScheduleConfig · object
required

Schedule constraints for when the campaign can run

description
string | null

Optional campaign description. Max 150 characters.

Maximum string length: 150

Response

Successful Response

Summary metadata for a campaign, returned in list responses.

name
string
required

Name of the resource

campaign_id
string
required

Unique identifier for the campaign

status
enum<string>
required

Current status

Available options:
ended,
active,
paused,
scheduled,
cancelled
app_id
string
required

ID of the agent

created_by
string
required

User who created this resource

created_at
string<date-time>
required

Timestamp when the resource was created (ISO 8601)

updated_at
string<date-time>
required

Timestamp when the resource was last updated (ISO 8601)

description
string | null

Optional description

app_type
enum<string>
default:agent

Type of agent

Available options:
agent
app_version
integer | null

Version of the agent to use

updated_by
string | null

User who last updated this resource