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.

POST/campaigns

https://calling.ubiqproject.com/api/v1/campaigns · Auth: API key (full access)

Request

Body

namestringrequired
A name for the campaign. At least 2 characters.
agent_idstring (UUID)required
The AI employee that makes the calls (from List AI employees).
phone_number_idstring (UUID)
The number to call from (from List phone numbers). Omit it to use the AI employee's own number.
concurrencyinteger
How many calls may run at the same time, 1–20. Default 5.
contactsobject[]
The people to call. Each needs a 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_nowboolean
true starts calling straight away (state running). Default false creates a draft that you start later.
configobject
Calling hours, retries, conditions and more — see config below. Default {}.
Request
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.

Response · 201
{
  "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)
The campaign's ID.
namestring
The campaign's name.
agent_idstring (UUID)
The AI employee that makes the calls.
agent_namestring
That AI employee's name.
phone_numberstring | null
The number calls are made from. null when the AI employee's own number is used.
created_bystring | null
Email of the dashboard user who created it. Empty when created with an API key.
concurrencyinteger
How many calls may run at the same time (1–20).
contacts_totalinteger
Every contact in the campaign, including ones your conditions filtered out.
contacts_doneinteger
Contacts whose call connected and finished.
contacts_failedinteger
Contacts that couldn't be reached after all attempts, plus contacts your conditions filtered out (never called).
contacts_pendinginteger
Contacts waiting to be called or on a call right now.
statestring
draft (not started), running, paused or done (every contact handled).
created_atstring (ISO 8601)
When it was created.
started_atstring | null
When it first started calling. null for a draft.
configobject
Calling hours, retries, conditions and more — see Create a campaign → config.

config

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

enabledboolean
Only call inside the window when true.
startstring
Window start, "HH:MM" 24-hour. Default "00:00".
stopstring
Window end, "HH:MM". Default "23:59".
timezonestring
An IANA time zone such as Asia/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

enabledboolean
Retry failed calls when true. Without it each contact is tried once.
max_attemptsinteger
Total attempts per contact, including the first. Default 3.
schedulestring
immediate (default — retry on the next pass), next_day (24 hours later) or custom (after days + hours).
days, hoursinteger
The wait for custom. 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.50 and 15% are read as numbers; a cell that isn't a number never matches.
  • empty, not_empty — no value needed.
  • in — value is a comma-separated list, such as "overdue, due today".
config.conditions
[
  { "column": "status", "op": "!=", "value": "paid" },
  { "column": "emi_amount", "op": ">=", "value": "1000" }
]

Conditions apply when contacts are added

Each contact is checked once, as it's added. Changing conditions later doesn't re-check contacts already in the campaign.

Other keys

Parameters

start_atstring
Start automatically at this local time, "2026-10-15T10:00", in start_tz. Works for a draft or paused campaign, and only once.
start_tzstring
IANA time zone for start_at. Default UTC.
number_poolstring[]
Extra phone-number IDs to rotate the caller ID through, in turn with phone_number_id.
greeting_variantsobject
A/B test the greeting: { "B": "Hi {{name}}, …" }. Contacts are split evenly between the AI employee's own greeting (A) and B. Up to 600 characters.
outcomesobject[]
The results to sort calls into, [{ "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 found404
The agent_id isn't one of your AI employees.
Phone number not found404
The phone_number_id isn't one of your numbers.
Invalid agent_id422
Not a UUID. Also "Invalid phone_number_id".
Validation list422
A missing name or agent_id, a name under 2 characters, or concurrency outside 1–20.

Check phone numbers before you send them

Contacts added here aren't checked for a valid phone format — a bad number is dialled, fails, and counts in contacts_failed. Send international numbers such as +919876543210. Send flat text or number values; they're stored as text.

Starting with no contacts

A campaign started with no contacts finishes (state done) almost at once. Create it as a draft, add contacts, then start it.