Create a campaign with a name, a from_number you own and either a message (audio_type of audio or tts) for broadcast, or a queue_id for an agent dialer. Then upload contacts, optionally test and estimate it, and call POST/v1/campaigns/{id}/start. The portal's four-step campaign wizard does the same.
1. Create#
curl -X POST https://voice-api.edesy.in/v1/campaigns \
-H "Authorization: Bearer $EDESY_KEY" \
-H "Content-Type: application/json" \
-d '{
"name": "Diwali offer",
"from_number": "+9180XXXXXXXX",
"fallback_from_number": "+9180YYYYYYYY",
"audio_type": "tts",
"tts_text": "Namaste! Acme Diwali sale is live. Visit our store this week for 20 percent off.",
"tts_language": "hi-IN",
"max_concurrent": 10,
"retry_attempts": 2,
"retry_delay_sec": 1800,
"ring_timeout_sec": 30,
"amd_enabled": true,
"recording_enabled": false,
"window_start_minute": 600,
"window_end_minute": 1200,
"timezone": "Asia/Kolkata"
}'
| Field | Type | Required | Description |
|---|---|---|---|
name |
string | Required | Campaign name |
from_number |
string | Required | Caller ID; a number in your workspace |
fallback_from_number |
string | Optional | Backup caller ID used while the main one's carrier is refusing calls. Omit to use the workspace default; "" means none |
audio_type |
string | broadcast | audio (upload a file) or tts |
tts_text, tts_voice, tts_language |
string | for tts |
Message text, voice and language |
max_concurrent |
integer | Optional | Simultaneous calls |
retry_attempts, retry_delay_sec |
integer | Optional | Retries for unanswered contacts, and the gap between them |
ring_timeout_sec |
integer | Optional | Seconds to ring each contact |
amd_enabled |
boolean | Optional | Answering-machine detection |
recording_enabled |
boolean | Optional | Record calls |
scheduled_at |
RFC 3339 | Optional | Start time |
window_start_minute, window_end_minute |
integer | Optional | Daily calling window in minutes after midnight. Default 540 to 1260 (09:00 to 21:00) |
timezone |
string | Optional | Timezone for the window, for example Asia/Kolkata |
queue_id |
UUID | agent dialer | Contact-center queue whose free agents take answered calls |
dial_ratio |
number | Optional | Agent dialer lines per free agent: 1.0 (progressive, default), 1.5 or 2.0 (power) |
The response is the campaign object in data with its id and status.
2. Add the message (broadcast with audio)#
curl -X POST https://voice-api.edesy.in/v1/campaigns/{id}/audio \
-H "Authorization: Bearer $EDESY_KEY" \
-F "[email protected]"
WAV or MP3.
3. Add contacts#
CSV (multipart field contacts):
curl -X POST https://voice-api.edesy.in/v1/campaigns/{id}/contacts \
-H "Authorization: Bearer $EDESY_KEY" \
-F "[email protected]"
phone_number,name,consent_source,consent_timestamp
+9198XXXXXXXX,Asha,website_form,2026-10-01T10:00:00Z
+9197XXXXXXXX,Ravi,,
The phone column may be named phone_number, phone, number, mobile or msisdn; the name column name or contact_name. consent_source and consent_timestamp are optional and kept for your compliance export.
Or JSON:
{ "contacts": [ { "phone_number": "+9198XXXXXXXX", "name": "Asha" } ] }
The response accounts for every row:
{
"data": {
"contacts_added": 1,
"total_rows": 2,
"suppressed_dnc": 1,
"suppressed_duplicate": 0,
"invalid": 0,
"invalid_samples": [],
"consent_timestamp_unparsed": 0
}
}
4. Test, estimate, start#
# Hear the message on your own phone
curl -X POST https://voice-api.edesy.in/v1/campaigns/{id}/test-call \
-H "Authorization: Bearer $EDESY_KEY" -H "Content-Type: application/json" \
-d '{ "phone_number": "+9198XXXXXXXX" }'
# Cost and duration estimate
curl https://voice-api.edesy.in/v1/campaigns/{id}/estimate -H "Authorization: Bearer $EDESY_KEY"
# Start now
curl -X POST https://voice-api.edesy.in/v1/campaigns/{id}/start -H "Authorization: Bearer $EDESY_KEY"
To start later, POST/v1/campaigns/{id}/schedule with scheduled_at (and optionally a new window, or "clear_window": true to remove it). DELETE/v1/campaigns/{id}/schedule cancels the schedule.
Control#
| Action | Endpoint |
|---|---|
| Pause / resume | POST/v1/campaigns/{id}/pause, /resume |
| Stop for good | POST/v1/campaigns/{id}/stop |
| Run again | POST/v1/campaigns/{id}/duplicate with {"audience": "all"}, "unreached" or "none" |
See also AMD, Fallback Caller ID and DNC and Estimate and Results.