Place phone calls from Python in a few lines.
Text-to-speech calls · press-1 voice broadcasts · live AI voice agents · auto local-presence caller ID.
voicepilot is the official Python SDK for the Zcall voice API. Sign up, grab an API key, add a little balance, and start dialing — no PBX, SIP trunk, or carrier contract. A developer-friendly, pay-as-you-go alternative to Twilio, Vonage, Plivo, and Bland.
- 📞 Real outbound calls from code — one function, one call. Or a whole list.
- 🗣️ Text-to-speech — speak any message; pick a voice and language.
- ☎️ Press-1 voice broadcasts — blast a message and transfer anyone who presses 1 to a live agent.
- 🤖 Live AI voice agents — natural, real-time conversations that qualify leads, confirm bookings, or take messages.
- 🌍 Auto local-presence caller ID — omit the caller ID and each call presents a number in the destination's own country (answered far more often).
- ⚡ Guaranteed-CLI routes to 100+ destinations, crypto-friendly, pay-as-you-go.
pip install voicepilotRequires Python 3.8+ and requests. Published on PyPI — upgrade any time with pip install -U voicepilot.
- Create an account at zcall.io and copy your API key (Dashboard → Settings → API).
- Add a little balance.
- Place a call:
from voicepilot import VoicePilot
vp = VoicePilot(api_key="zc_live_...") # or set the VOICEPILOT_API_KEY env var
# Text-to-speech call. No caller_id -> a local-presence number for the
# destination's country is chosen automatically.
batch = vp.calls.say(
to="+14155551234",
message="Hi! This call was placed from Python with voicepilot.",
)
print(f"launched {batch.launched}/{batch.total} from {batch.caller_id}")Call one number or many. Pass a voice_id / language to control how it sounds.
vp.calls.say(
to=["+14155551234", "+447700900123"],
message="Your appointment is confirmed for Tuesday at 3 PM.",
language="en",
)Broadcast a spoken message to a list; anyone who presses 1 is transferred to your agent SIP user(s) — tried in order, first online wins.
batch = vp.calls.say(
to=["+14155551234", "+447700900123", "+9779812345678"],
message="This is a courtesy call about your account. Press 1 to speak with us.",
press1_transfer_to=["1001", "1002"],
)
# With no caller_id, each country gets its own local-presence caller ID.
print(f"{batch.launched} calls across {len(batch.campaigns)} caller IDs")A real-time AI agent driven by your prompt. It talks, listens, and can hand off to a human.
vp.calls.ai(
to="+14155551234",
prompt="You are a friendly clinic receptionist. Confirm the caller's "
"appointment for Tuesday at 3 PM and offer to reschedule.",
first_message="Hi, this is Riverside Clinic calling to confirm your appointment.",
transfer_to=["1001"], # if the caller asks for a human
# elevenlabs_api_key="sk_...", # optional: run on your own ElevenLabs account
)Leave caller_id out and voicepilot presents a number matching each destination's country. You can also generate one yourself:
from voicepilot import local_presence_caller_id
local_presence_caller_id("+447700900123") # -> "+44…" (a UK number)
local_presence_caller_id("+14155551234") # -> "+1…" (a US number)Acceptable use. Only present a caller ID you are authorised to use, and follow the caller-ID and telemarketing rules for everywhere you call and call from (e.g. US TRACED Act / TCPA, UK Ofcom CLI, EU/GDPR). You are responsible for how you use this.
for row in batch.results(): # per-call status + DTMF (1 = pressed)
print(row["destination"], row["status"], row.get("dtmf"))
vp.calls.stats() # totals + answer rate
vp.balance() # live balance
vp.rates() # live per-minute rates (no auth needed)
vp.voices("en") # available voicesPay-as-you-go — no subscription, no minimums, and your balance never expires.
| What | Price |
|---|---|
| Create an account | Free |
| Outbound & TTS calls | from $0.05 / min — varies by destination |
| Press-1 voice broadcast | standard per-minute call rate |
| Live AI voice agent | $0.30 / min — or no surcharge with your own ElevenLabs key |
| Subscription / minimums | None — prepaid, balance never expires |
| Payment | Cards & crypto · billed in USD |
Rates are indicative. See live per-destination pricing at zcall.io.
| Method | Description |
|---|---|
vp.calls.say(to, message, *, caller_id=None, voice_id=None, language="en", press1_transfer_to=None) |
TTS call to one/many numbers; press-1 transfer |
vp.calls.ai(to, prompt, *, first_message=None, transfer_to=None, elevenlabs_api_key=None, ...) |
Live AI voice-agent call |
vp.calls.launch(flow_id, to, *, caller_id=None) |
Launch a saved flow |
batch.results() · vp.calls.results(campaign_id) |
Per-call status + DTMF |
vp.calls.stats() |
Answer-rate / totals |
vp.flows.create(...) · .list() · .delete(id) |
Manage reusable flows |
vp.balance() |
Live account balance |
vp.rates() |
Live per-minute rates (no auth) |
vp.voices(lang) · vp.languages() |
Available voices / languages |
vp.set_caller_id(cid) |
Set your default outbound caller ID |
Full REST reference: zcall.io/docs.
Every error subclasses VoicePilotError:
from voicepilot import VoicePilot, AuthenticationError, InsufficientBalanceError
try:
vp.calls.say(to="+14155551234", message="Hello")
except InsufficientBalanceError:
print("Top up your balance at zcall.io")
except AuthenticationError:
print("Check your API key")- 🌐 Website — zcall.io
- 📚 API docs — zcall.io/docs
- 💬 Support (Telegram) — t.me/zcall_admin
MIT © Zcall. See LICENSE.