Give your AI agent the ability to make real phone calls.
call-use is an open-source outbound call-control runtime that lets AI agents dial real phones, navigate IVR menus, talk to humans, and return structured results. Think browser-use, but for phone calls.
Early release (v0.1) — Core functionality works. API may change before v1.0. Report issues.
from call_use import CallAgent
outcome = await CallAgent(
phone="+18001234567",
instructions="Cancel my internet subscription",
approval_required=False,
).call()
print(outcome.disposition) # "completed"
print(outcome.transcript) # [{speaker: "agent", text: "..."}, ...]- Four interfaces — Python SDK, CLI, MCP server, and REST API. Use whichever fits your stack.
- IVR navigation — Navigate phone menus, press DTMF buttons, handle hold music automatically.
- Human takeover — Pause the AI mid-call, join as a human, then hand control back to the agent.
- Approval flow — Agent pauses and asks permission before taking sensitive actions.
- Structured outcomes — Every call returns typed results: transcript, events, disposition, duration.
- Phone validation — E.164 format enforcement, premium-rate blocking, Caribbean NPA blocking.
- Framework integrations — Works with LangChain, CrewAI, OpenAI Agents, and any MCP-compatible client.
- Rate limiting — Built-in per-key sliding window for the REST API.
pip install call-usecall-use connects four external services into a voice AI pipeline:
| Service | Purpose | Sign up |
|---|---|---|
| LiveKit | Real-time audio transport + agent dispatch | Cloud or self-hosted |
| Twilio | SIP trunk for PSTN connectivity | Console |
| Deepgram | Speech-to-text | Console |
| OpenAI | LLM (GPT-4o) + text-to-speech | Platform |
Set these environment variables (or use a .env file):
| Variable | Description |
|---|---|
LIVEKIT_URL |
LiveKit server URL (wss://...) |
LIVEKIT_API_KEY |
LiveKit API key |
LIVEKIT_API_SECRET |
LiveKit API secret |
SIP_TRUNK_ID |
Twilio SIP trunk ID configured in LiveKit |
DEEPGRAM_API_KEY |
Deepgram API key for STT |
OPENAI_API_KEY |
OpenAI API key for LLM + TTS |
The worker process handles the actual voice pipeline:
call-use-worker startPython SDK:
import asyncio
from call_use import CallAgent
async def main():
agent = CallAgent(
phone="+18001234567",
instructions="Ask about store hours",
approval_required=False,
)
outcome = await agent.call()
print(f"{outcome.disposition.value}: {outcome.duration_seconds:.0f}s")
for t in outcome.transcript:
print(f" [{t['speaker']}] {t['text']}")
asyncio.run(main())CLI — any agent that can run shell commands can make calls:
call-use dial "+18001234567" -i "Ask about store hours"Events stream to stderr in real-time; structured JSON result goes to stdout.
MCP Server — native integration for Claude Code, Codex, and other MCP clients:
{
"mcpServers": {
"call-use": {
"command": "call-use-mcp",
"env": {
"LIVEKIT_URL": "wss://...",
"LIVEKIT_API_KEY": "...",
"LIVEKIT_API_SECRET": "...",
"SIP_TRUNK_ID": "...",
"DEEPGRAM_API_KEY": "your-deepgram-api-key",
"OPENAI_API_KEY": "..."
}
}
}
}Exposes four async tools: dial (returns immediately), status, cancel, result.
┌──────────┐ ┌──────────────┐ ┌────────────┐ ┌──────┐
│ Your Code│────────▶│ LiveKit Cloud│────────▶│ Twilio SIP │────────▶│ PSTN │
│ (SDK/CLI)│ gRPC │ │ agent │ │ SIP │ │
└──────────┘ │ Room + Data │ dispatch │ │ ☎ │
│ Channels │ └────────────┘ └──────┘
└──────┬───────┘
│
┌──────┴───────┐
│ call-use │
│ worker │
│ │
│ Deepgram STT │
│ GPT-4o LLM │
│ OpenAI TTS │
└──────────────┘
Two processes: your code dispatches a call task into a LiveKit room; the worker joins the room, dials via SIP, runs the voice conversation, and publishes the structured outcome.
Pause the AI agent, join the call yourself, then hand control back:
call_task = asyncio.create_task(agent.call())
# ... when a human needs to take over:
token = await agent.takeover() # returns LiveKit JWT
# ... join the room with the token, talk to the callee ...
await agent.resume() # agent takes over again
result = await call_taskThe agent pauses and asks before taking sensitive actions:
agent = CallAgent(
phone="+18001234567",
instructions="Cancel my subscription. If they offer a discount, ask me first.",
approval_required=True,
on_approval=lambda data: "approved" if input(f"Approve '{data['details']}'? [y/n]: ").strip().lower() == "y" else "rejected",
)For multi-tenant deployments:
from call_use import create_app
app = create_app(api_key="your-secret-key")
# uvicorn your_module:app| Method | Path | Description |
|---|---|---|
POST |
/calls |
Create outbound call |
GET |
/calls/{id} |
Get call status |
POST |
/calls/{id}/inject |
Inject context into active call |
POST |
/calls/{id}/takeover |
Human takeover |
POST |
/calls/{id}/resume |
Resume AI agent |
POST |
/calls/{id}/approve |
Approve pending action |
POST |
/calls/{id}/reject |
Reject pending action |
POST |
/calls/{id}/cancel |
Cancel call |
All endpoints require an X-API-Key header.
| Example | Description |
|---|---|
| Customer service refund | End-to-end refund automation |
| Appointment scheduler | Navigate IVR, book appointment |
| Insurance claim | File claim, capture claim number |
| Subscription cancellation | Handle retention offers via approval flow |
| Multi-call workflow | Chain sequential calls |
| Webhook integration | FastAPI + WebSocket events |
| LangChain tool | Use as a LangChain tool |
| OpenAI Agents | OpenAI Agents SDK integration |
| CrewAI | PhoneCallTool for CrewAI |
| Claude Code MCP | MCP server setup guide |
Full documentation at docs.call-use.com — getting started, guides, API reference, and architecture deep-dive.
git clone https://github.com/agent-next/call-use.git
cd call-use
pip install -e ".[dev]"
make check # lint + typecheck + test (100% coverage) + buildSee CONTRIBUTING.md for guidelines.
| Problem | Cause | Fix |
|---|---|---|
MissingEnvironmentError on startup |
One or more required env vars are unset | Ensure all six variables from the Configuration table are exported (or present in your .env file). Run call-use doctor to check. |
| LiveKit connection failed / timeout | LIVEKIT_URL is wrong or the LiveKit server is unreachable |
Verify LIVEKIT_URL starts with wss://, and that the LiveKit server (Cloud or self-hosted) is running and reachable from your network. |
| Worker not picking up calls | The worker process is not running | Start it with call-use-worker start in a separate terminal. |
| Call times out immediately | SIP trunk is misconfigured in LiveKit | Double-check SIP_TRUNK_ID matches an active Twilio SIP trunk in your LiveKit dashboard. Ensure the trunk's origination URI points to your LiveKit instance. |
PermissionError writing log files |
~/.call-use/logs/ has restrictive permissions |
Run chmod 755 ~/.call-use/logs/ or set CALL_USE_LOG_DIR to a writable directory. |
- In-memory state — REST API call state is lost on restart; use LiveKit room metadata for recovery.
- Single worker — Horizontal scaling requires a shared state backend.
- US/Canada only — Outbound PSTN via Twilio SIP; international and inbound calling are planned.
call-use is a developer tool for legitimate business automation. Users are solely responsible for complying with all applicable telecommunications laws including TCPA, FCC regulations on AI-generated voices (FCC 24-17), Do Not Call registry, and state recording consent laws. See SECURITY.md for details.