Skip to main content
Use this guide when your CRM, data warehouse, or backend decides who to call and you want Callers to do the calling. You build the agent once in the dashboard, then your system pushes contacts, controls when the agent runs, and receives every outcome by webhook.

Before you begin

How outbound dialing works

Once an agent is active, Callers continuously picks eligible contacts and calls them:
  • Calls only go out inside the agent’s availability hours, in the agent’s time zone or the contact’s time zone if Use Contact’s Time Zone is on.
  • Unanswered, busy, and voicemail attempts are retried according to the agent’s retry settings (total attempts, minimum wait between attempts, maximum attempts per day).
  • Concurrency is capped by the agent’s Max Outgoing Calls in Parallel setting.
  • Contacts on your Do Not Call list are skipped.
  • Contacts you add while the agent is running are picked up automatically.
  • When no eligible contacts remain, the agent stops on its own. Adding new contacts to a completed agent makes it eligible to run again; call start if it’s stopped.

Step 1: Map your data to variables

Every key in a contact’s data object becomes a variable your script can use as {{key}}. Before sending contacts, list the variables your script uses and make sure each contact provides them. Variables marked required in the agent must be present. A single-contact request missing one fails with 400; in a bulk request the incomplete contact is skipped.
Send a timezone (IANA name such as America/Chicago) per contact if you know it. Otherwise Callers detects the time zone from the phone number.

Step 2: Push contacts

Use the bulk endpoint for anything beyond a single contact. JSON bodies are limited to 1 MB, so split large lists into batches (a few hundred to a thousand contacts per request, depending on how much data each carries) and send them sequentially.
Store the returned contactId next to your own record (or put your record ID in data, like crm_id above) so you can match webhook results later. Re-sending a contact with the same phone number updates it instead of creating a duplicate, so retries are safe. See Manage contacts for the full behavior, multiple phone numbers per contact, and validation errors.

Step 3: Start and stop the agent

start on an active agent returns 400 Campaign already activated. and stop on a stopped agent returns 400 Campaign not activated.. Check active with GET /agents/{agentId} first, or treat those responses as success.
Stopping an agent pauses new calls. It doesn’t remove contacts or reset their attempts; starting again continues where it left off.

Step 4: Receive outcomes

Subscribe a webhook to the events you need. A typical outbound integration uses: Subscribe through the dashboard or the API:
The API subscribe endpoint accepts the standard call events. To subscribe to CONTACT_UNREACHED, CONTACT_LAST_DAILY_ATTEMPT, or events for custom success criteria, configure the webhook in the agent’s Webhooks settings in the dashboard.
Match each payload to your record with contact.id, contact.phoneNumber, or a value you put in contact.data. See Webhook events and Webhook payload.

Step 5: Track progress

Poll sparingly; webhooks are the primary signal. For dashboards and reconciliation:
The report for an outbound agent counts contacts by status, plus call totals:
Response
For an inbound agent, contactsByStatuses counts calls instead (COMPLETED, IN_PROGRESS, ANALYZING, INTERESTED, NOT_INTERESTED, FAILED) and there is no totalContacts or answeredCallsCount.

List calls

GET /agents/{agentId}/calls returns the agent’s calls as a plain array, newest first, with page and perPage (default 50):
Each call includes id, sessionId, contactId, agentId (and the legacy campaignId), status, hangUpReason, duration, createdAt, phoneFrom, phoneTo, messages, summary, goal, events, and recordingUrl when available. Keep paging until a page comes back with fewer than perPage items.

Download a call’s SIP trace

For calls placed over your own SIP trunk, GET /agents/{agentId}/calls/{callId}/pcap returns the packet capture of the SIP signaling (application/vnd.tcpdump.pcap). Share it with your carrier when you debug one-way audio or rejected calls. It’s only available for SIP calls and only for recent ones; otherwise the endpoint returns 404.

Step 6: Stop calling specific people

When someone converts or opts out in your system, archive them so the agent stops calling. Archived contacts are kept (with their history) and can be restored.

Correct an outcome

If your team learns that a call’s outcome was wrong, set it from your system:
callStatus accepts INTERESTED, NOT_INTERESTED, VOICE_MAIL, CALL_ME_LATER, DO_NOT_CALL, WRONG_NUMBER, or COMPLETED. Pass callReachedGoal with a success criterion’s name (for example, callReachedGoal=Demo%20Scheduled) to record which criterion was met.

Backfill missed webhooks

If your endpoint was down, you don’t have to guess what you missed. List the agent’s calls, then fetch the exact webhook payload for each one with GET /agents/{agentId}/calls/{callId}/webhook-payload and run it through the same handler your webhook uses. The payload matches the final delivery (its webhookEvent is the current state of the call), so skip calls you already have by id.
Node.js
Add a short delay between requests for large backfills, and don’t run this in a tight loop on a schedule: webhooks remain the primary signal.

Best practices

  • One agent per use case. Keep script, schedule, and success criteria specific. Use agent groups to organize many agents.
  • Push contacts ahead of the calling window so the agent can start dialing as soon as hours open.
  • Store Callers IDs. Save contactId and the call id from webhooks to make reconciliation and re-fetching easy.
  • Backfill from the API. If your endpoint was down, list calls with GET /agents/{agentId}/calls and fetch each payload with GET /agents/{agentId}/calls/{callId}/webhook-payload. See Backfill missed webhooks.
  • Test first. Run a few contacts (your own numbers) through the agent before loading a full list.

Troubleshooting

Some contacts were skipped: invalid or missing phone numbers, missing name, or missing required variables. Validate numbers before sending, or use fixUSPhoneNumber=true for 10-digit US numbers without a country code.
At least one contact has invalid data (non-string value, invalid key, too large). Invalid data on any contact rejects the whole request; each issue includes the contact’s index in path.
It ran out of eligible contacts. Add more contacts and call start. Also check the agent in the dashboard for a failure reason (for example, a missing phone number).
Re-uploading updates the existing contact and keeps its status. If it had been archived, re-uploading restores it (unless you send "archived": true), and it can be called again if it still has attempts left.

Manage contacts

Validation, duplicates, filters, and archiving.

Scheduling and retries

Availability hours, retry rules, and concurrency.

Webhook events

Every event and when it fires.

Statuses and outcomes

What each call and contact status means.