Campaigns API
Create and manage outbound voice and SMS campaigns with AMD, voicemail deposit, live AI agent handoff, and human-like SMS drip sending.
Campaigns orchestrate large-scale outbound voice calling and SMS messaging. Voice campaigns include automatic answering machine detection (AMD), voicemail audio deposit, and live AI agent handoff. SMS campaigns send messages with human-like pacing (3-5 per DID per hour). Both channels share the same DID rotation, health monitoring, compliance enforcement, and retry logic.
Campaign lifecycle
Campaign status flow: created → dialing → completed | paused | cancelled | failed
A paused campaign can be resumed back to dialing.
Create campaign
POST /api/campaigns
curl -X POST https://api.trunx.io/api/campaigns \
-H "Authorization: Bearer tk_live_..." \
-H "Content-Type: application/json" \
-d '{
"name": "Q1 SoCal Outreach",
"channel": "voice",
"mode": {
"ai": true,
"voicemailAudioUrl": "https://example.com/vm.mp3",
"calls_per_second": 10,
"max_retries": 2,
"retry_delay": "4h"
},
"callerIds": ["+19495551000", "+17145551000"],
"callerIdStrategy": {
"selection": "health_score",
"local_presence": true
},
"schedule": {
"timezone": "America/Los_Angeles",
"startHour": 9,
"endHour": 19,
"days": [1, 2, 3, 4, 5]
}
}'curl -X POST https://api.trunx.io/api/campaigns \
-H "Authorization: Bearer tk_live_..." \
-H "Content-Type: application/json" \
-d '{
"name": "March Follow-Up Texts",
"channel": "sms",
"mode": {
"message": "Hi, this is Trunx following up on your inquiry. Reply YES to schedule a call."
},
"callerIds": ["+19495551000", "+17145551000"],
"schedule": {
"timezone": "America/Los_Angeles"
}
}'const res = await fetch("https://api.trunx.io/api/campaigns", {
method: "POST",
headers: {
"Authorization": "Bearer tk_live_...",
"Content-Type": "application/json",
},
body: JSON.stringify({
name: "Q1 SoCal Outreach",
channel: "voice", // or "sms"
mode: {
ai: true,
voicemailAudioUrl: "https://example.com/vm.mp3",
calls_per_second: 10,
max_retries: 2,
retry_delay: "4h",
},
callerIds: ["+19495551000", "+17145551000"],
callerIdStrategy: {
selection: "health_score",
local_presence: true,
},
schedule: {
timezone: "America/Los_Angeles",
startHour: 9,
endHour: 19,
days: [1, 2, 3, 4, 5],
},
}),
});
const data = await res.json();import requests
res = requests.post(
"https://api.trunx.io/api/campaigns",
headers={"Authorization": "Bearer tk_live_..."},
json={
"name": "Q1 SoCal Outreach",
"channel": "voice", # or "sms"
"mode": {
"ai": True,
"voicemailAudioUrl": "https://example.com/vm.mp3",
"calls_per_second": 10,
"max_retries": 2,
"retry_delay": "4h",
},
"callerIds": ["+19495551000", "+17145551000"],
"callerIdStrategy": {
"selection": "health_score",
"local_presence": True,
},
"schedule": {
"timezone": "America/Los_Angeles",
"startHour": 9,
"endHour": 19,
"days": [1, 2, 3, 4, 5],
},
},
)
data = res.json()Response
{
"id": "camp_abc123",
"name": "Q1 SoCal Outreach",
"status": "created",
"channel": "voice"
}Request body
| Field | Type | Required | Description |
|---|---|---|---|
name | string | Yes | Campaign name (min 1 character) |
channel | string | No | "voice" (default) or "sms" |
mode | object | No | Channel-specific configuration (see below) |
callerIds | string[] | No | E.164 phone numbers or area codes to use as caller IDs |
callerIdStrategy | object | No | DID selection and rotation strategy |
schedule | object | No | TCPA-compliant schedule |
Mode options (voice)
| Field | Type | Description |
|---|---|---|
ai | boolean | Enable AI agent for live calls |
voicemailAudioUrl | string | URL of audio to play when voicemail is detected |
calls_per_second | number | Dialing rate limit |
max_retries | number | Maximum retry attempts per prospect |
retry_delay | string | Delay between retries (e.g. "4h", "30m") |
Mode options (SMS)
| Field | Type | Description |
|---|---|---|
message | string | Required. The SMS body text to send to each prospect |
SMS campaigns enforce a stricter sending window (7 AM – 7 PM) and throttle to ~4 messages per DID per hour with 15-minute gaps for human-like pacing. Delivery status is tracked automatically via carrier webhooks.
Schedule
| Field | Type | Description |
|---|---|---|
timezone | string | IANA timezone (e.g. "America/Los_Angeles") |
startHour | number | Daily start hour (0-23) |
endHour | number | Daily end hour (0-23) |
days | number[] | Days of week (1=Monday through 7=Sunday) |
TCPA compliance is enforced at the infrastructure level. Calls outside the configured schedule window or to numbers on the suppression list will be automatically blocked.
List campaigns
GET /api/campaigns
Returns all campaigns for the authenticated account.
curl "https://api.trunx.io/api/campaigns" \
-H "Authorization: Bearer tk_live_..."const res = await fetch("https://api.trunx.io/api/campaigns", {
headers: { "Authorization": "Bearer tk_live_..." },
});
const data = await res.json();import requests
res = requests.get(
"https://api.trunx.io/api/campaigns",
headers={"Authorization": "Bearer tk_live_..."},
)
data = res.json()Response
{
"campaigns": [
{ "id": "camp_abc123", "name": "Q1 SoCal Outreach", "status": "dialing", "channel": "voice" },
{ "id": "camp_def456", "name": "March Follow-Up Texts", "status": "created", "channel": "sms" }
]
}Get campaign
GET /api/campaigns/:id
Returns the full campaign object with real-time stats.
curl "https://api.trunx.io/api/campaigns/camp_abc123" \
-H "Authorization: Bearer tk_live_..."const res = await fetch("https://api.trunx.io/api/campaigns/camp_abc123", {
headers: { "Authorization": "Bearer tk_live_..." },
});
const data = await res.json();import requests
res = requests.get(
"https://api.trunx.io/api/campaigns/camp_abc123",
headers={"Authorization": "Bearer tk_live_..."},
)
data = res.json()Response
{
"id": "camp_abc123",
"name": "Q1 SoCal Outreach",
"status": "dialing",
"channel": "voice",
"stats": {
"total": 5000,
"queued": 2100,
"dialing": 10,
"completed": 2890,
"failed": 49,
"cancelled": 0,
"noAnswer": 284,
"busy": 42,
"voicemail": 2312,
"humanConnected": 203,
"sending": 0,
"sent": 0,
"delivered": 0,
"progress": 57
}
}Campaign lifecycle actions
Start campaign
POST /api/campaigns/:id/start
Begins dialing (voice) or sending (SMS). The campaign must be in created status. SMS campaigns must have mode.message set.
Pause campaign
POST /api/campaigns/:id/pause
Pauses an active campaign. In-progress calls complete but no new calls are placed. Campaign must be in dialing status.
Resume campaign
POST /api/campaigns/:id/resume
Resumes a paused campaign from where it left off. Campaign must be in paused status.
Cancel campaign
POST /api/campaigns/:id/cancel
Permanently stops the campaign. All queued prospects are marked as cancelled.
All lifecycle actions return { id, name, status, channel }.
# Start a campaign
curl -X POST "https://api.trunx.io/api/campaigns/camp_abc123/start" \
-H "Authorization: Bearer tk_live_..."
# Pause a campaign
curl -X POST "https://api.trunx.io/api/campaigns/camp_abc123/pause" \
-H "Authorization: Bearer tk_live_..."
# Resume a campaign
curl -X POST "https://api.trunx.io/api/campaigns/camp_abc123/resume" \
-H "Authorization: Bearer tk_live_..."
# Cancel a campaign
curl -X POST "https://api.trunx.io/api/campaigns/camp_abc123/cancel" \
-H "Authorization: Bearer tk_live_..."// Start a campaign
await fetch("https://api.trunx.io/api/campaigns/camp_abc123/start", {
method: "POST",
headers: { "Authorization": "Bearer tk_live_..." },
});
// Pause
await fetch("https://api.trunx.io/api/campaigns/camp_abc123/pause", {
method: "POST",
headers: { "Authorization": "Bearer tk_live_..." },
});import requests
headers = {"Authorization": "Bearer tk_live_..."}
# Start a campaign
requests.post("https://api.trunx.io/api/campaigns/camp_abc123/start", headers=headers)
# Pause
requests.post("https://api.trunx.io/api/campaigns/camp_abc123/pause", headers=headers)Response (all actions)
{
"id": "camp_abc123",
"name": "Q1 SoCal Outreach",
"status": "dialing",
"channel": "voice"
}Prospects
Add prospects
POST /api/campaigns/:id/prospects
Add phone numbers to a campaign. Can only add prospects when the campaign is in created or paused status. Accepts 1 to 10,000 phone numbers per request.
curl -X POST "https://api.trunx.io/api/campaigns/camp_abc123/prospects" \
-H "Authorization: Bearer tk_live_..." \
-H "Content-Type: application/json" \
-d '{
"phones": [
"+17145551001",
"+16195551002",
"+18185551003"
]
}'const res = await fetch("https://api.trunx.io/api/campaigns/camp_abc123/prospects", {
method: "POST",
headers: {
"Authorization": "Bearer tk_live_...",
"Content-Type": "application/json",
},
body: JSON.stringify({
phones: ["+17145551001", "+16195551002", "+18185551003"],
}),
});
const data = await res.json();import requests
res = requests.post(
"https://api.trunx.io/api/campaigns/camp_abc123/prospects",
headers={"Authorization": "Bearer tk_live_..."},
json={
"phones": ["+17145551001", "+16195551002", "+18185551003"]
},
)
data = res.json()Response
{
"added": 3
}Phone numbers must be in E.164 format (e.g. +14155551234). Prospects are automatically checked against the suppression list (DNC) during dialing.
List prospects
GET /api/campaigns/:id/prospects
Returns all prospects for the campaign.
{
"prospects": [
{ "id": "...", "campaignId": "camp_abc123", "phone": "+17145551001", "status": "queued" },
{ "id": "...", "campaignId": "camp_abc123", "phone": "+16195551002", "status": "dialing" }
]
}Campaign stats
GET /api/campaigns/:id/stats
Returns real-time campaign statistics. All field names use camelCase.
curl "https://api.trunx.io/api/campaigns/camp_abc123/stats" \
-H "Authorization: Bearer tk_live_..."const res = await fetch("https://api.trunx.io/api/campaigns/camp_abc123/stats", {
headers: { "Authorization": "Bearer tk_live_..." },
});
const data = await res.json();import requests
res = requests.get(
"https://api.trunx.io/api/campaigns/camp_abc123/stats",
headers={"Authorization": "Bearer tk_live_..."},
)
data = res.json()Response
{
"total": 5000,
"queued": 2100,
"dialing": 10,
"completed": 2890,
"failed": 49,
"cancelled": 0,
"noAnswer": 284,
"busy": 42,
"voicemail": 2312,
"humanConnected": 203,
"sending": 0,
"sent": 0,
"delivered": 0,
"progress": 57
}Fields
| Field | Type | Description |
|---|---|---|
total | number | Total prospects in the campaign |
queued | number | Waiting to be dialed/sent |
dialing | number | Voice call currently in-progress |
completed | number | Finished (any terminal outcome including delivered) |
failed | number | Call/message failed |
cancelled | number | Cancelled before dialing/sending |
noAnswer | number | No pickup within ring timeout (voice only) |
busy | number | Line busy (voice only) |
voicemail | number | AMD detected machine (voice only) |
humanConnected | number | Human answered (voice only) |
sending | number | SMS being sent (SMS only) |
sent | number | SMS sent, awaiting delivery confirmation (SMS only) |
delivered | number | SMS delivered to recipient (SMS only) |
progress | number | Completion percentage (0-100) |