Outbound calls are calls your system initiates - rather than waiting for a caller to ring in. Common use cases:
Appointment reminders
Sales outreach campaigns
Callback queues
Alert notifications
Outbound calls use the same Speech Pipe, voice profile, and AgentRunner infrastructure as inbound calls. The difference is you trigger them via the management API.
import asynciofrom unpod import AsyncClientasync def main(): async with AsyncClient(api_key="sk-...") as client: call = await client.calls.create( pipe_id="pipe_...", to_number="+14155550100", # E.164 format from_number="+18005551234", # optional if a number is attached to the Speech Pipe instructions="This is a reminder call for a dental appointment.", data={ "patient_name": "Jane Smith", "appointment_date": "2026-06-10", "appointment_time": "09:30 AM", "doctor": "Dr. Patel", }, ) print("Call initiated:", call.call_id, call.status) # status is "pending" - calls.create() enqueues the call and returns # immediately. The call is dispatched asynchronously once the account # has free concurrency. Poll GET /calls/{id} (or use hooks) to watch # it advance to ringing -> active -> completed. See Call Lifecycle.asyncio.run(main())
calls.create() is asynchronous: it enqueues the call and returns a record
with status="pending". The call is dispatched on a worker as soon as your
account has free concurrency. See Call Lifecycle for
the full status progression and how to poll for completion.
import asynciofrom unpod import AsyncClientasync def main(): async with AsyncClient(api_key="sk-...") as client: # All outbound calls for a Speech Pipe calls = await client.calls.list( pipe_id="pipe_...", status="completed", ) for c in calls: print(c.id, c.to_number, c.status, c.duration_s)asyncio.run(main())
Batch dialing at high rates may trigger carrier spam filters. Use a sensible interval between calls and comply with local regulations (TCPA in the US, etc.).
import asynciofrom unpod import AsyncClientasync def process_callback_queue(queue: list[dict]) -> None: async with AsyncClient(api_key="sk-...") as client: for request in queue: # Check if the Speech Pipe is not at capacity before dialing # (AgentRunner handles capacity internally - orchestrator rejects if full) call = await client.calls.create( pipe_id="pipe_...", to_number=request["phone"], from_number="+18005551234", instructions="This is a callback. The customer requested to be called back.", data={"ticket_id": request["ticket_id"], "reason": request["reason"]}, ) await db.update_callback_request( request["id"], call_id=call.call_id, status="dialing", )