curl --request POST \
--url https://prod-api.ringg.ai/ca/api/v0/campaign/save \
--header 'Content-Type: multipart/form-data' \
--header 'X-API-KEY: <api-key>' \
--form 'variables_map={
"callee_name": "Name",
"company_name": "Company"
}' \
--form agent_id=00000000-0000-4000-8000-0000000000a1 \
--form 'call_config={
"idle_timeout_warning": 10,
"max_call_length": 300
}' \
--form 'country_code=+91' \
--form 'campaign_start_time=18/10/2025, 09:00' \
--form 'campaign_end_time=18/10/2025, 21:05' \
--form 'campaign_name=Q1 Sales Campaign' \
--form file=@example-file \
--form remove_invalid_rows=false \
--form transliterate_callee_name=false \
--form 'transliterate_fields=["callee_name"]'import requests
url = "https://prod-api.ringg.ai/ca/api/v0/campaign/save"
files = { "file": ("example-file", open("example-file", "rb")) }
payload = {
"variables_map": "{
\"callee_name\": \"Name\",
\"company_name\": \"Company\"
}",
"agent_id": "00000000-0000-4000-8000-0000000000a1",
"call_config": "{
\"idle_timeout_warning\": 10,
\"max_call_length\": 300
}",
"country_code": "+91",
"campaign_start_time": "18/10/2025, 09:00",
"campaign_end_time": "18/10/2025, 21:05",
"campaign_name": "Q1 Sales Campaign",
"remove_invalid_rows": "false",
"transliterate_callee_name": "false",
"transliterate_fields": "[\"callee_name\"]"
}
headers = {"X-API-KEY": "<api-key>"}
response = requests.post(url, data=payload, files=files, headers=headers)
print(response.text)const form = new FormData();
form.append('variables_map', '{
"callee_name": "Name",
"company_name": "Company"
}');
form.append('agent_id', '00000000-0000-4000-8000-0000000000a1');
form.append('call_config', '{
"idle_timeout_warning": 10,
"max_call_length": 300
}');
form.append('country_code', '+91');
form.append('campaign_start_time', '18/10/2025, 09:00');
form.append('campaign_end_time', '18/10/2025, 21:05');
form.append('campaign_name', 'Q1 Sales Campaign');
form.append('file', 'contacts.csv');
form.append('remove_invalid_rows', 'false');
form.append('transliterate_callee_name', 'false');
form.append('transliterate_fields', '["callee_name"]');
const options = {method: 'POST', headers: {'X-API-KEY': '<api-key>'}};
options.body = form;
fetch('https://prod-api.ringg.ai/ca/api/v0/campaign/save', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));{
"message": "Contacts imported successfully!",
"list_id": "123e4567-e89b-12d3-a456-426614174000",
"custom_args_values": [
{
"callee_name": "John Doe",
"company_name": "XYZ Corp",
"mobile_number": "+1234567890"
}
],
"total_rows": 100,
"successful_rows": 98,
"failed_rows": 2
}{
"message": "Invalid file format."
}{
"message": "Invalid credentials"
}{
"message": "You can only upload up to 100 contacts."
}{
"message": "An unexpected error occurred. Please try again later."
}Upload Campaign Contact List
Upload a campaign calling list as CSV with the agent, variable mapping, country code, campaign window and call settings, and get the list_id to start it with.
curl --request POST \
--url https://prod-api.ringg.ai/ca/api/v0/campaign/save \
--header 'Content-Type: multipart/form-data' \
--header 'X-API-KEY: <api-key>' \
--form 'variables_map={
"callee_name": "Name",
"company_name": "Company"
}' \
--form agent_id=00000000-0000-4000-8000-0000000000a1 \
--form 'call_config={
"idle_timeout_warning": 10,
"max_call_length": 300
}' \
--form 'country_code=+91' \
--form 'campaign_start_time=18/10/2025, 09:00' \
--form 'campaign_end_time=18/10/2025, 21:05' \
--form 'campaign_name=Q1 Sales Campaign' \
--form file=@example-file \
--form remove_invalid_rows=false \
--form transliterate_callee_name=false \
--form 'transliterate_fields=["callee_name"]'import requests
url = "https://prod-api.ringg.ai/ca/api/v0/campaign/save"
files = { "file": ("example-file", open("example-file", "rb")) }
payload = {
"variables_map": "{
\"callee_name\": \"Name\",
\"company_name\": \"Company\"
}",
"agent_id": "00000000-0000-4000-8000-0000000000a1",
"call_config": "{
\"idle_timeout_warning\": 10,
\"max_call_length\": 300
}",
"country_code": "+91",
"campaign_start_time": "18/10/2025, 09:00",
"campaign_end_time": "18/10/2025, 21:05",
"campaign_name": "Q1 Sales Campaign",
"remove_invalid_rows": "false",
"transliterate_callee_name": "false",
"transliterate_fields": "[\"callee_name\"]"
}
headers = {"X-API-KEY": "<api-key>"}
response = requests.post(url, data=payload, files=files, headers=headers)
print(response.text)const form = new FormData();
form.append('variables_map', '{
"callee_name": "Name",
"company_name": "Company"
}');
form.append('agent_id', '00000000-0000-4000-8000-0000000000a1');
form.append('call_config', '{
"idle_timeout_warning": 10,
"max_call_length": 300
}');
form.append('country_code', '+91');
form.append('campaign_start_time', '18/10/2025, 09:00');
form.append('campaign_end_time', '18/10/2025, 21:05');
form.append('campaign_name', 'Q1 Sales Campaign');
form.append('file', 'contacts.csv');
form.append('remove_invalid_rows', 'false');
form.append('transliterate_callee_name', 'false');
form.append('transliterate_fields', '["callee_name"]');
const options = {method: 'POST', headers: {'X-API-KEY': '<api-key>'}};
options.body = form;
fetch('https://prod-api.ringg.ai/ca/api/v0/campaign/save', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));{
"message": "Contacts imported successfully!",
"list_id": "123e4567-e89b-12d3-a456-426614174000",
"custom_args_values": [
{
"callee_name": "John Doe",
"company_name": "XYZ Corp",
"mobile_number": "+1234567890"
}
],
"total_rows": 100,
"successful_rows": 98,
"failed_rows": 2
}{
"message": "Invalid file format."
}{
"message": "Invalid credentials"
}{
"message": "You can only upload up to 100 contacts."
}{
"message": "An unexpected error occurred. Please try again later."
}list_id is also the campaign’s ID in Get all campaigns, call history and analytics (bulk_list_id).
The CSV
One header row, then one row per contact. Every outbound agent has the variablesmobile_number and callee_name, so the file needs a column for each, plus one for every other variable the agent’s prompt uses. Write phone numbers without the country code; country_code applies to the whole list.
callee_name,mobile_number,amount_due,due_date
Priya Sharma,9876543210,4500,12 October
Rahul Verma,9876540123,1200,15 October
Fields
campaign_start_time and campaign_end_time are read in call_config.call_time.timezone, and the start must be in the future. Without remove_invalid_rows, a row that fails validation fails the whole upload with 400, and the uploader is emailed the errors. A list may have up to 100 rows by default, and up to 5,000 once Company details are saved in the dashboard; a longer list returns 402.
transliterate_fields is a JSON array of the agent’s own variable names, not CSV headers, whose values are transliterated into the agent’s language; each must be mapped in variables_map, and mobile_number is not allowed. transliterate_callee_name=true is the same as adding callee_name; both can be sent.
variables_map for the CSV above:
{"callee_name": "callee_name", "mobile_number": "mobile_number", "amount_due": "amount_due", "due_date": "due_date"}
call_config is a JSON string with the daily window calls may be placed in and how failed calls are retried. Retry waits are in minutes.
{
"call_time": { "call_start_time": "09:00", "call_end_time": "18:00", "timezone": "Asia/Kolkata" },
"call_retry_config": { "retry_count": 2, "retry_busy": 30, "retry_not_picked": 30, "retry_failed": 30 }
}
Response
{
"message": "Contacts imported successfully!",
"list_id": "123e4567-e89b-12d3-a456-426614174000",
"total_rows": 100,
"successful_rows": 98,
"failed_rows": 2
}
Authorizations
Headers
(Required) Your Ringg AI API key.
"rg_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
Body
(Required) JSON string mapping variable names to columns
{
"callee_name": "Name",
"company_name": "Company"
}
(Required) Unique identifier for the agent
"00000000-0000-4000-8000-0000000000a1"
(Required) JSON string of call configuration
{
"idle_timeout_warning": 10,
"max_call_length": 300
}
(Required) Phone number country code (e.g., +91 for India, +1 for US)
"+91"
(Required) Start time for the campaign (DD/MM/YYYY, HH:MM format)
"18/10/2025, 09:00"
(Required) End time for the campaign (DD/MM/YYYY, HH:MM format)
"18/10/2025, 21:05"
(Required) Name of the campaign.
"Q1 Sales Campaign"
(Required) CSV file containing the contact list.
(Optional) When true, invalid rows are left out. When false, any invalid row fails the whole upload with 400 and the uploader is emailed the errors.
false
(Optional) Transliterate callee_name into the agent's language. Same as adding callee_name to transliterate_fields. A row whose name cannot be transliterated is dropped as invalid.
false
(Optional) JSON string array of the agent's own variable names (not CSV headers) whose values are transliterated into the agent's language, for example ["callee_name"]. Each must be mapped in variables_map; mobile_number is refused with 400. The original value stays available as original_<field>. Combined with transliterate_callee_name when both are sent.
"[\"callee_name\"]"
Response
Contact list uploaded and campaign saved successfully.
"Contacts imported successfully!"
ID of the created campaign list
"123e4567-e89b-12d3-a456-426614174000"
Array of custom variables for each contact
[
{
"callee_name": "John Doe",
"company_name": "XYZ Corp",
"mobile_number": "+1234567890"
}
]
Total number of rows in uploaded CSV
100
Number of successfully processed rows
98
Number of rows that failed validation
2
Was this page helpful?