Skip to main content

Outbound Call Dispatch

The Outbound Call Dispatch API queues one or more outbound calls for a published voice agent. Dispatch is asynchronous: the API returns 202 Accepted immediately with a batch identifier, and you poll a status endpoint to track each call as it dials, completes, or fails.

When to Use This

  • Place outbound calls programmatically from your backend, CRM, or scheduler.
  • Dial a list of numbers in one request and track them as a single batch.
  • Retry safely with an idempotency key so duplicate requests don't dispatch twice.

Prerequisites

  • A published voice agent with an active outbound FROM number configured under Call Configuration → Outbound Settings. Drafts and unpublished agents cannot be dispatched.
  • An API Key with the Voice Agent scope. If the key uses a specific Agent Access list, the target agent_id must be on that list.

Authentication

Every request must include the api-key header — see API Keys for how to generate and manage tokens.

api-key: sk_<your-secret>

A missing, invalid, disabled, expired, scope-mismatched, or agent-denied key fails with 401/403 and is recorded in Request Logs with a matching error code.

Create a dispatch

POST /voice/outbound/dispatch

Headers

HeaderRequiredDescription
api-keyYesYour API key secret (must have Voice Agent scope)
Content-TypeYesapplication/json
Idempotency-KeyNoFree-form string. Repeating the same key returns the original batch_id instead of creating a new batch. See Idempotency below.

Body

FieldTypeRequiredDescription
agent_idstringYesUUID of the published voice agent to dispatch from
destination_phonenumberstring or array of stringsYesOne or more destination numbers in E.164 format (e.g., +14155551234). Up to 500 numbers per request by default.
metadataobjectNoFree-form key/value pairs attached to the batch — surfaced in observability events for your own correlation

Example request

curl -X POST https://<your-dronahq-host>/voice/outbound/dispatch \
-H "api-key: sk_your-generated-secret-here" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: campaign-2026-06-23-batch-7" \
-d '{
"agent_id": "<voice-agent-uuid>",
"destination_phonenumber": [
"+14155551234",
"+919876543210"
],
"metadata": {
"campaign_id": "spring-renewal",
"tier": "premium"
}
}'

Response — 202 Accepted

FieldTypeDescription
batch_idstringUUID for this batch; use it with the status endpoint below
acceptedintegerCount of numbers accepted into the batch
status_urlstringRelative URL to poll for batch status
{
"batch_id": "f0c1a3f2-9e1c-4b21-9b8b-5a9c0f0a1e3a",
"accepted": 2,
"status_url": "/voice/outbound/dispatch/f0c1a3f2-9e1c-4b21-9b8b-5a9c0f0a1e3a"
}

Get batch status

GET /voice/outbound/dispatch/{batch_id}

Returns the current state of every call in the batch.

Headers

HeaderRequiredDescription
api-keyYesSame key requirements as create — must have Voice Agent scope and access to the batch's agent_id

Example response — 200 OK

{
"batch_id": "f0c1a3f2-9e1c-4b21-9b8b-5a9c0f0a1e3a",
"agent_id": "a1d3...",
"created_at": "2026-06-23T10:14:02Z",
"total": 2,
"queued": 0,
"dialing": 1,
"completed": 1,
"failed": 0,
"retrying": 0,
"calls": [
{
"index": 0,
"phone_number": "+14155551234",
"status": "completed",
"attempts": 1,
"error_code": null,
"error_message": null,
"started_at": "2026-06-23T10:14:05Z",
"completed_at": "2026-06-23T10:15:22Z"
},
{
"index": 1,
"phone_number": "+919876543210",
"status": "dialing",
"attempts": 1,
"error_code": null,
"error_message": null,
"started_at": "2026-06-23T10:14:05Z",
"completed_at": null
}
]
}

Call status values

StatusMeaning
queuedWaiting in the dispatcher queue, not yet dialed
dialingProvider has been asked to place the call
completedCall connected and ended normally
failedCall failed permanently; error_code and error_message describe why
retryingCall failed with a retriable error and will be retried (subject to the retry budget)

Idempotency

Send Idempotency-Key: <your-string> on the create request to make retries safe. If you re-send the same Idempotency-Key, the API returns the original batch's batch_id and accepted count instead of dispatching a second time.

Use any stable string your system can regenerate on retry — a campaign-batch ID, a job ID from your scheduler, or a UUID you store before the call.

Limits

LimitDefaultNotes
Numbers per request500Requests exceeding this fail with 400.
Concurrent calls per worker2Beyond this, calls stay in queued until a slot frees.
Retry attempts per call3Only applies to retriable failures (see below).

Defaults are operator-configurable; check with your administrator if you need them tuned.

Errors

API errors (entire request fails)

HTTP statusCauseFix
400Too many numbers in one requestSplit into batches of ≤ 500
400Agent is not published, or has no outbound FROM numberPublish the agent and pick an outbound number in Call Configuration → Outbound Settings
400A number isn't valid E.164Use +<country><number>, digits only
401 / 403Auth failure on the API keySee the error-code chip in Request Logs (missing_token, invalid_token, disabled, expired, scope_denied, agent_denied)
404agent_id not found, or batch_id not found on the status endpointDouble-check the UUID; the batch may have aged out

Per-call error codes

When a single call inside a batch fails, the call's error_code is one of:

CodeRetriable?Meaning
INVALID_NUMBERNoNumber was rejected by the carrier as malformed or unreachable
PROVIDER_REJECTEDNoTelephony provider refused to place the call (geo block, balance, etc.)
PROVIDER_UNAVAILABLEYesProvider was temporarily unreachable
NO_ANSWERNoCall rang out without being picked up
BUSYYesRecipient line was busy
AGENT_FAILED_TO_JOINYesThe voice agent didn't join the room in time
LIVEKIT_ERRORYesUnderlying LiveKit session failed
TIMEOUTYesOperation exceeded its time budget
INTERNAL_ERRORYesUnexpected failure inside DronaHQ

Retriable codes are attempted again automatically up to the retry budget; non-retriable codes terminate the call as failed immediately.