API Reference · Campaigns
Create a campaign
Creates a campaign: one AI employee calling a list of contacts, at the pace and hours you choose. Send the contacts in the same request, or add them afterwards as a CSV file.
/campaignshttps://calling.ubiqproject.com/api/v1/campaigns · Auth: API key (full access)
Request
Body
namestringrequiredagent_idstring (UUID)requiredphone_number_idstring (UUID)concurrencyinteger1–20. Default 5.contactsobject[]phone (or phone_number) in international format; every other field becomes a {{placeholder}} the AI employee can use, such as {{name}}. Rows without a phone are dropped. Default [].start_nowbooleantrue starts calling straight away (state running). Default false creates a draft that you start later.configobject{}.curl -X POST https://calling.ubiqproject.com/api/v1/campaigns \
-H "Authorization: Bearer vk_live_YOUR_KEY" \
-H "Content-Type: application/json" \
-d '{
"name": "October EMI reminders",
"agent_id": "3f8c2a1e-6b4d-4c7a-9e21-5d0f7b8a9c34",
"phone_number_id": "a71d9e04-2c3b-4f58-8e6a-1b9c0d2e3f47",
"concurrency": 5,
"contacts": [
{ "phone": "+919876543210", "name": "Rahul Verma", "emi_amount": "4500", "due_date": "15 Oct" },
{ "phone": "+919812345678", "name": "Anita Desai", "emi_amount": "12000", "due_date": "18 Oct" },
{ "phone": "+919898012345", "name": "Imran Khan", "emi_amount": "7800", "due_date": "20 Oct" }
],
"config": {
"daily": { "enabled": true, "start": "10:00", "stop": "19:00", "timezone": "Asia/Kolkata" },
"retry": { "enabled": true, "max_attempts": 3, "schedule": "custom", "days": 0, "hours": 2 }
}
}'Response
201 Created with the new campaign.
{
"id": "9b4e6f12-8a3c-4d71-b05e-2f6a8c1d7e93",
"name": "October EMI reminders",
"agent_id": "3f8c2a1e-6b4d-4c7a-9e21-5d0f7b8a9c34",
"agent_name": "Priya",
"phone_number": "+918046801234",
"created_by": "",
"concurrency": 5,
"contacts_total": 3,
"contacts_done": 0,
"contacts_failed": 0,
"contacts_pending": 3,
"state": "draft",
"created_at": "2026-10-08T09:14:22.512341Z",
"started_at": null,
"config": {
"daily": {
"enabled": true,
"start": "10:00",
"stop": "19:00",
"timezone": "Asia/Kolkata"
},
"retry": {
"enabled": true,
"max_attempts": 3,
"schedule": "custom",
"days": 0,
"hours": 2
}
}
}Response fields
idstring (UUID)namestringagent_idstring (UUID)agent_namestringphone_numberstring | nullcreated_bystring | nullconcurrencyintegercontacts_totalintegercontacts_doneintegercontacts_failedintegercontacts_pendingintegerstatestringdraft (not started), running, paused or done (every contact handled).created_atstring (ISO 8601)started_atstring | nullconfigobjectconfig
Every key is optional. Anything you leave out uses the default: call at any hour, no retries, call every contact. You can change these later with Update settings.
daily — calling hours
Parameters
enabledbooleantrue.startstring"HH:MM" 24-hour. Default "00:00".stopstring"HH:MM". Default "23:59".timezonestringAsia/Kolkata. Default UTC.Outside the window the campaign stays running but places no new calls; it carries on when the window opens.
retry — call again when nobody answers
Parameters
enabledbooleantrue. Without it each contact is tried once.max_attemptsinteger3.schedulestringimmediate (default — retry on the next pass), next_day (24 hours later) or custom (after days + hours).days, hoursintegercustom. Default 0.A retry is only made for calls that didn't go through — no answer, busy, or a dialling error.
conditions — who to call
A list of { column, op, value }. A contact is called only if it matches all of them; the rest are kept but never called.
=,!=,contains— text, ignoring upper/lower case and surrounding spaces.<,>,>=,<=— numbers.₹ 4,500,$99.50and15%are read as numbers; a cell that isn't a number never matches.empty,not_empty— novalueneeded.in—valueis a comma-separated list, such as"overdue, due today".
[
{ "column": "status", "op": "!=", "value": "paid" },
{ "column": "emi_amount", "op": ">=", "value": "1000" }
]Conditions apply when contacts are added
conditions later doesn't re-check contacts already in the campaign.Other keys
Parameters
start_atstring"2026-10-15T10:00", in start_tz. Works for a draft or paused campaign, and only once.start_tzstringstart_at. Default UTC.number_poolstring[]phone_number_id.greeting_variantsobject{ "B": "Hi {{name}}, …" }. Contacts are split evenly between the AI employee's own greeting (A) and B. Up to 600 characters.outcomesobject[][{ "key": "promise_to_pay", "label": "Promised to pay" }]. After each call Daffy Voice reads the transcript and picks one key. Without it, Daffy Voice uses interested, not_interested, promise_to_pay, callback, wrong_number, no_answer, other.Workflows write more keys here (follow-up actions, captured details, results delivery). Build those in a workflow rather than by hand.
Errors
Responses
Agent not found404agent_id isn't one of your AI employees.Phone number not found404phone_number_id isn't one of your numbers.Invalid agent_id422"Invalid phone_number_id".Validation list422name or agent_id, a name under 2 characters, or concurrency outside 1–20.Check phone numbers before you send them
contacts_failed. Send international numbers such as +919876543210. Send flat text or number values; they're stored as text.Starting with no contacts
done) almost at once. Create it as a draft, add contacts, then start it.