> ## Documentation Index
> Fetch the complete documentation index at: https://docs.ringg.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Setting Up Bulk Calls

> Upload a campaign CSV, map variables, start outbound calls, and monitor campaign results.

Bulk calls are campaign-driven in Ringg. For most campaigns, create the campaign with `POST /campaign/save`, then start it with `POST /campaign/start`.

<Info>
  For CSVs with 5,000 or more rows, use the beta large-campaign flow after it is enabled for your workspace. That path uploads and validates the CSV asynchronously before starting calls.
</Info>

## Prerequisites

* A workspace API key
* An outbound assistant ID
* One or more workspace number IDs
* A CSV file with a `Mobile Number` column and any assistant variables

## Choose the campaign flow

| Use case           | Flow                     | Endpoints                                                                                                                                                  |
| ------------------ | ------------------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Most campaign CSVs | Standard campaign flow   | `POST /campaign/save` then `POST /campaign/start`                                                                                                          |
| 5,000+ row CSVs    | Beta large-campaign flow | `POST /campaign/upload-csv`, `GET /campaign/upload-status/{bulk_list_id}`, `POST /campaign/check-balance/{bulk_list_id}`, `POST /campaign/make-call-async` |

## Step 1: Prepare the CSV

Use the exact template from the Ringg dashboard when possible. At minimum, include the recipient number and every variable your assistant prompt uses.

```text theme={null}
Mobile Number,Name,Policy ID,Due Date
+919876543210,John Doe,POL-123,20/10/2026
+919876543211,Jane Smith,POL-124,21/10/2026
```

## Standard flow

### Step 2: Upload the campaign contact list

`POST /campaign/save` accepts `multipart/form-data`. Do not set `Content-Type` manually in browser or Node `FormData` clients; let the client set the multipart boundary.

```javascript theme={null}
const formData = new FormData();
formData.append("variables_map", JSON.stringify({
  mobile_number: "Mobile Number",
  callee_name: "Name",
  policy_id: "Policy ID",
  due_date: "Due Date"
}));
formData.append("agent_id", process.env.RINGG_AGENT_ID);
formData.append("country_code", "+91");
formData.append("campaign_name", "Renewal reminders");
formData.append("campaign_start_time", "18/10/2026, 09:00");
formData.append("campaign_end_time", "18/10/2026, 18:00");
formData.append("call_config", JSON.stringify({
  call_time: {
    call_start_time: "09:00",
    call_end_time: "18:00",
    timezone: "Asia/Kolkata"
  },
  call_retry_config: {
    retry_count: 1,
    retry_busy: 30,
    retry_not_picked: 30,
    retry_failed: 30
  }
}));
formData.append("file", csvFile);

const uploadResponse = await fetch("https://prod-api.ringg.ai/ca/api/v0/campaign/save", {
  method: "POST",
  headers: {
    "X-API-KEY": process.env.RINGG_API_KEY
  },
  body: formData
});

const uploadedCampaign = await uploadResponse.json();
console.log(uploadedCampaign.list_id);
```

Save the returned `list_id`; it is required to start the campaign.

### Step 3: Choose caller numbers

```bash theme={null}
curl --request GET "https://prod-api.ringg.ai/ca/api/v0/workspace/numbers" \
  --header "X-API-KEY: $RINGG_API_KEY"
```

Pick one or more number IDs to use as `from_numbers`.

### Step 4: Start the campaign

```bash theme={null}
curl --request POST "https://prod-api.ringg.ai/ca/api/v0/campaign/start" \
  --header "X-API-KEY: $RINGG_API_KEY" \
  --header "Content-Type: application/json" \
  --data '{
    "agent_id": "your-agent-id",
    "list_id": "your-list-id",
    "from_numbers": ["your-from-number-id"],
    "callback_url": "https://api.example.com/ringg/campaign-callback"
  }'
```

### Step 5: Monitor campaign calls

Use campaign and history endpoints together:

```bash theme={null}
curl --request GET "https://prod-api.ringg.ai/ca/api/v0/campaign/all?call_count=true" \
  --header "X-API-KEY: $RINGG_API_KEY"
```

```bash theme={null}
curl --request GET "https://prod-api.ringg.ai/ca/api/v0/calling/history?bulk_list_id=your-list-id" \
  --header "X-API-KEY: $RINGG_API_KEY"
```

### Step 6: Stop calls if needed

Use termination endpoints for emergency stops or selective campaign cleanup.

```bash theme={null}
curl --request PATCH "https://prod-api.ringg.ai/ca/api/v0/campaign/terminate" \
  --header "X-API-KEY: $RINGG_API_KEY" \
  --header "Content-Type: application/json" \
  --data '{
    "campaign_id": "your-list-id"
  }'
```

## Beta large-campaign flow

Use this path for CSVs with 5,000 or more rows. It separates upload, validation, balance checking, and call scheduling so long CSV imports do not block one request.

<Warning>
  This flow is beta. Use the standard `POST /campaign/save` plus `POST /campaign/start` flow unless large-campaign beta access is enabled for your workspace.
</Warning>

### Beta step 1: Upload the CSV

`POST /campaign/upload-csv` accepts the large CSV and campaign metadata. Use the same CSV headers, variable mapping, assistant ID, campaign window, country code, and call configuration you would send to `POST /campaign/save`.

```bash theme={null}
curl --request POST "https://prod-api.ringg.ai/ca/api/v0/campaign/upload-csv" \
  --header "X-API-KEY: $RINGG_API_KEY" \
  --form 'agent_id="your-agent-id"' \
  --form 'campaign_name="Renewal reminders - large batch"' \
  --form 'country_code="+91"' \
  --form 'variables_map="{\"mobile_number\":\"Mobile Number\",\"callee_name\":\"Name\"}"' \
  --form 'campaign_start_time="18/10/2026, 09:00"' \
  --form 'campaign_end_time="18/10/2026, 18:00"' \
  --form 'call_config="{\"call_time\":{\"call_start_time\":\"09:00\",\"call_end_time\":\"18:00\",\"timezone\":\"Asia/Kolkata\"}}"' \
  --form "file=@contacts-5000-plus.csv"
```

Save the returned `bulk_list_id`. Use it for every following beta step.

### Beta step 2: Poll upload status

```bash theme={null}
curl --request GET "https://prod-api.ringg.ai/ca/api/v0/campaign/upload-status/your-bulk-list-id" \
  --header "X-API-KEY: $RINGG_API_KEY"
```

Wait until processing is complete before checking balance or starting calls. If the status reports invalid rows, fix the CSV or remove invalid rows according to your campaign policy.

### Beta step 3: Check balance

```bash theme={null}
curl --request POST "https://prod-api.ringg.ai/ca/api/v0/campaign/check-balance/your-bulk-list-id" \
  --header "X-API-KEY: $RINGG_API_KEY"
```

Only continue when the response confirms the workspace has enough balance for the validated rows.

### Beta step 4: Start calls asynchronously

```bash theme={null}
curl --request POST "https://prod-api.ringg.ai/ca/api/v0/campaign/make-call-async" \
  --header "X-API-KEY: $RINGG_API_KEY" \
  --header "Content-Type: application/json" \
  --data '{
    "agent_id": "your-agent-id",
    "bulk_list_id": "your-bulk-list-id",
    "from_numbers": ["your-from-number-id"],
    "callback_url": "https://api.example.com/ringg/campaign-callback"
  }'
```

After scheduling, monitor the campaign with `GET /campaign/all` and call history filtered by the same `bulk_list_id`.

<CardGroup cols={2}>
  <Card title="Upload large campaign CSV" icon="upload" href="/api-reference/endpoint/campaign/upload-large-campaign-csv">
    Start the beta 5k+ row import.
  </Card>

  <Card title="Check upload status" icon="activity" href="/api-reference/endpoint/campaign/get-large-campaign-upload-status">
    Poll CSV processing before starting calls.
  </Card>

  <Card title="Check campaign balance" icon="wallet" href="/api-reference/endpoint/campaign/check-large-campaign-balance">
    Confirm available balance for the validated contacts.
  </Card>

  <Card title="Start async campaign calls" icon="phone-call" href="/api-reference/endpoint/campaign/make-large-campaign-calls-async">
    Queue the large campaign for outbound calling.
  </Card>
</CardGroup>

## Production checklist

* Start with a small CSV before uploading a large campaign.
* Set campaign windows in the audience's timezone.
* Validate CSV headers before upload.
* Store `list_id` and selected `from_numbers`.
* Store `bulk_list_id` for beta large campaigns.
* Subscribe to webhooks for post-call results.
* Use `remove_invalid_rows=true` when you prefer skipping invalid contacts instead of failing the whole upload.
