You’ll need a HTTP service that can receive incoming call hooks and trigger a new agent session. We discussed the concept of a bot runner in the deployment section, which we’ll build on here to add support for incoming phone calls.
Here’s how to implement this with FastAPI:
server.py
Copy
Ask AI
@app.post("/call", response_class=PlainTextResponse)async def handle_call(request: Request): """Handle incoming Twilio call webhook.""" print("Received call webhook from Twilio") try: # Get form data from Twilio webhook form_data = await request.form() data = dict(form_data) # Extract call ID (required to forward the call later) call_sid = data.get("CallSid") if not call_sid: raise HTTPException(status_code=400, detail="Missing CallSid in request") print(f"Processing call with ID: {call_sid}") # 1. Create a Daily room with SIP capabilities # More on this in the next section room_details = await create_sip_room(request.app.session) room_url = room_details["room_url"] token = room_details["token"] sip_endpoint = room_details["sip_endpoint"] # 2. Start the bot process with the necessary parameters bot_cmd = f"python bot.py -u {room_url} -t {token} -i {call_sid} -s {sip_endpoint}" subprocess.Popen(shlex.split(bot_cmd)) print(f"Started bot process with command: {bot_cmd}") # 3. IMPORTANT: Put the caller on hold with music while the bot initializes # This is critical to avoid timing issues with Daily SIP initialization resp = VoiceResponse() resp.play( url="https://your-hold-music.mp3", # Your custom hold music URL loop=10, # Loop the music until the bot is ready ) return str(resp) except Exception as e: print(f"Unexpected error: {str(e)}") raise HTTPException(status_code=500, detail=f"Server error: {str(e)}")
We’ll need to configure the Daily room to be setup to receive SIP connections. In our example project, utils/daily-helpers.py demonstrates how to set up the Daily room using the Daily REST helpers available in Pipecat. We just need to pass through new SIP parameters as part of room creation:
utils/daily_helpers.py
Copy
Ask AI
async def create_sip_room(session: Optional[aiohttp.ClientSession] = None) -> Dict[str, str]: """Create a Daily room with SIP capabilities for phone calls.""" daily_helper = await get_daily_helper(session) # Configure SIP parameters sip_params = DailyRoomSipParams( display_name="phone-user", # This can be customized with caller info video=False, # Audio-only call sip_mode="dial-in", # For receiving calls num_endpoints=1, # Number of SIP endpoints needed ) # Create room properties with SIP enabled properties = DailyRoomProperties( sip=sip_params, enable_dialout=True, # For future expansion if needed start_video_off=True, # Voice only ) # Create and return the room room = await daily_helper.create_room(DailyRoomParams(properties=properties)) token = await daily_helper.get_token(room.url, 24 * 60 * 60) # 24 hours validity return { "room_url": room.url, "token": token, "sip_endpoint": room.config.sip_endpoint }
Your bot needs to handle the on_dialin_ready event to forward the call at the right time:
bot.py
Copy
Ask AI
async def run_bot(room_url: str, token: str, call_id: str, sip_uri: str) -> None: """Run the voice bot with the given parameters.""" logger.info(f"Starting bot with room: {room_url}") logger.info(f"SIP endpoint: {sip_uri}") # IMPORTANT: Track if call has been forwarded to avoid multiple forwards call_already_forwarded = False # Setup the Daily transport transport = DailyTransport( room_url, token, "Phone Bot", DailyParams( audio_in_enabled=True, audio_out_enabled=True, transcription_enabled=True, vad_analyzer=SileroVADAnalyzer(), ), ) # ... rest of your bot setup code ... # Handle call ready to forward @transport.event_handler("on_dialin_ready") async def on_dialin_ready(transport, cdata): nonlocal call_already_forwarded # We only want to forward the call once # The on_dialin_ready event will be triggered for each SIP endpoint if call_already_forwarded: logger.warning("Call already forwarded, ignoring this event.") return logger.info(f"Forwarding call {call_id} to {sip_uri}") try: # Update the Twilio call with TwiML to forward to the Daily SIP endpoint twilio_client.calls(call_id).update( twiml=f"<Response><Dial timeout=\"30\"><Sip>{sip_uri}</Sip></Dial></Response>" ) logger.info("Call forwarded successfully") call_already_forwarded = True except Exception as e: logger.error(f"Failed to forward call: {str(e)}") raise
For local development, you can use ngrok to expose your local server:
Copy
Ask AI
# Start your serverpython server.py# In another terminal, start ngrokngrok http 8000# Use the ngrok URL (e.g., https://a1b2c3.ngrok.io/call) as your webhook