Guides
Campaigns
Call a list of people at a pace you set, only in calling hours, and hear how each call went.
A campaign is a list of people for an outbound agent to call, at the pace you set and only in the hours you allow. It is the same campaign the console shows on the agent's Campaigns tab: one you start through the API, a colleague can pause in the console, and the other way round.
Campaigns call real people, so making or changing one needs a live key with campaigns:write,
and reading them needs campaigns:read. A test key reads no campaigns. To try your integration
first, schedule single calls to the test numbers.
Create one
#!/bin/sh
# Create a campaign. With a live key: a campaign calls real people. It is a draft until you start it.
curl -sS --fail-with-body -X POST "https://api.aigently.ai/v1/campaigns" \
-H "Authorization: Bearer $AIGENTLY_API_KEY" \
-H "Idempotency-Key: reminders-october" \
--json '{
"agent_id": "8a1f3c2e-0b6d-4f5e-9a7c-2d4e6f8a0b1c",
"name": "Visit reminders, October",
"calling_hours": {
"start_hour": 9,
"end_hour": 18,
"days": [
"mon",
"tue",
"wed",
"thu",
"fri"
]
},
"contacts": [
{
"to_number": "+12025550123",
"variables": {
"first_name": "Sara"
},
"metadata": {
"crm_lead_id": "L-20931"
},
"external_id": "lead-20931"
},
{
"to_number": "+12025550124",
"variables": {
"first_name": "Omar"
},
"timezone": "America/Chicago",
"external_id": "lead-20932"
}
]
}'
Each contact is one person: to_number, their variables, and if you like their timezone, your
own metadata and an external_id. Everything is checked before anything is made. A number the
platform does not call, the same number twice, a time zone that is not one, or a value that does
not fit the agent is refused with validation_failed, and errors names each contact by its place
in the list — contacts[3].variables.renewal_date. Up to 1,000 contacts go in one request; send the
rest as more people.
Idempotency-Key is required. A retry with the same key returns the campaign the first attempt
made, and never makes a second one that would call everybody twice. See
Safe retries.
| Field | What it is |
|---|---|
pacing |
max_concurrent calls at once, dials_per_minute, max_attempts for each person, and retry_backoff_minutes between tries. |
calling_hours |
start_hour, end_hour and days, read in each contact's own timezone — or your organization's, for a contact without one. |
voicemail |
hang_up when a machine answers, or leave_message with the message to leave. |
callbacks |
Whether a person may ask the agent to call back at a time of their own. |
phone_number_id |
Which of the agent's numbers to call from. The agent's own unless you say. |
start, start_at |
Start now, or at a moment you choose. Leave both out to start it later. |
A campaign is a draft until it starts. Starting checks that it can place a call: the agent is
published, it has a number to call from, and every contact has the values the agent says out loud —
other than a field with a default, which fills in, or one that is not required. It also needs
somebody on its list: a campaign started with no contacts would finish at once, so it is refused
with campaign_empty. To send the contacts in batches, create it as a draft, add them, then start
it. A campaign with a start_at may be empty until then. If nobody is on its list when the time
comes, it starts and waits for its first contacts instead of finishing.
Start, pause, resume and cancel
#!/bin/sh
# Start a campaign
curl -sS --fail-with-body -X POST "https://api.aigently.ai/v1/campaigns/1c3e5a7b-9d0f-4b2c-8e4a-6c8e0a2c4e6b/start" \
-H "Authorization: Bearer $AIGENTLY_API_KEY"
#!/bin/sh
# Pause a campaign. Calls in progress carry on; nobody new is called until you resume it.
curl -sS --fail-with-body -X POST "https://api.aigently.ai/v1/campaigns/1c3e5a7b-9d0f-4b2c-8e4a-6c8e0a2c4e6b/pause" \
-H "Authorization: Bearer $AIGENTLY_API_KEY"
#!/bin/sh
# Resume a campaign
curl -sS --fail-with-body -X POST "https://api.aigently.ai/v1/campaigns/1c3e5a7b-9d0f-4b2c-8e4a-6c8e0a2c4e6b/resume" \
-H "Authorization: Bearer $AIGENTLY_API_KEY" \
--json '{
"reset_attempts": false
}'
#!/bin/sh
# Cancel a campaign. For good: nobody else on the list is called.
curl -sS --fail-with-body -X POST "https://api.aigently.ai/v1/campaigns/1c3e5a7b-9d0f-4b2c-8e4a-6c8e0a2c4e6b/cancel" \
-H "Authorization: Bearer $AIGENTLY_API_KEY"
Pausing stops new calls. Calls in progress carry on, and resuming picks up where it stopped; send
reset_attempts: true to give everybody not reached so far every try back. Cancelling stops it for
good. Each answers with the campaign, and one that has already happened answers it as it is, so a
retry is harmless. A campaign that has finished — completed or cancelled — answers
campaign_finished.
A campaign can pause itself, too: when your organization's calls for the day are used up, or when
calls cannot be placed at all. paused_reason says why, and resuming is your decision.
While the deployment has phone calls switched off, creating, starting and resuming a campaign are
refused with feature_disabled. Pausing and cancelling still work.
Add more people
#!/bin/sh
# Add people to a campaign. A number the campaign already holds is skipped, so sending a batch again is safe.
curl -sS --fail-with-body -X POST "https://api.aigently.ai/v1/campaigns/1c3e5a7b-9d0f-4b2c-8e4a-6c8e0a2c4e6b/contacts" \
-H "Authorization: Bearer $AIGENTLY_API_KEY" \
--json '{
"contacts": [
{
"to_number": "+12025550125",
"variables": {
"first_name": "Lina"
},
"external_id": "lead-20933"
}
]
}'
A campaign that is a draft, running or paused takes more contacts, and a running one calls them in
its next calling hours. A number the campaign already holds is skipped and listed in
already_in_campaign, so sending a batch again is safe, even while the first is still being added.
+15550100 and 15550100 are the same number. A campaign completes once nobody is left to call;
after that, start a new one.
See how it went
#!/bin/sh
# Read a campaign and its progress
curl -sS --fail-with-body -X GET "https://api.aigently.ai/v1/campaigns/1c3e5a7b-9d0f-4b2c-8e4a-6c8e0a2c4e6b" \
-H "Authorization: Bearer $AIGENTLY_API_KEY"
contacts counts the people in each state. List them, with how it went for each:
#!/bin/sh
# See how each call in a campaign went
curl -sS --fail-with-body -X GET "https://api.aigently.ai/v1/campaigns/1c3e5a7b-9d0f-4b2c-8e4a-6c8e0a2c4e6b/contacts?status=done" \
-H "Authorization: Bearer $AIGENTLY_API_KEY"
status |
What it means |
|---|---|
queued |
Waiting for their turn, or for their next try at next_attempt_at. |
dialing |
On a call now. |
done |
Reached — or a message was left on their machine. |
exhausted |
Every try was used without reaching them. |
failed |
Not called: the platform refused, and error says why — a number on your do-not-call list, for one. |
conversation_id is their latest conversation. Every conversation with them carries their
metadata, their external_id and the campaign_id, so a webhook about it can
be tied back to its lead.
All your campaigns, newest first:
#!/bin/sh
# List campaigns
curl -sS --fail-with-body -X GET "https://api.aigently.ai/v1/campaigns?limit=10" \
-H "Authorization: Bearer $AIGENTLY_API_KEY"
Hear about it
Five events, sent to live receivers only:
| Event | When |
|---|---|
campaign.started |
It started calling — at once, at its start time, or again after a pause. |
campaign.paused |
Paused by somebody, or by itself, with paused_reason. |
campaign.completed |
Nobody is left to call. |
campaign.cancelled |
Stopped for good. |
campaign.contact_finished |
One person's final result: done, exhausted or failed. |
Each carries the campaign, or the contact, as the API reads it. A contact's number, values and metadata are left out for a receiver that does not include values, as they are for conversations.
A campaign belongs to your organization, not to the key that made it: revoking the key does not stop it. Pause or cancel it instead.