After-hours Voicemail and Notification

View as Markdown

Handle calls outside business hours by collecting a message, transcribing it, and notifying the team.

Overview

This use case demonstrates:

  • Time-of-day routing (business hours vs. after hours)
  • Pre-answer connect during business hours
  • AI voicemail recording and transcription
  • Database storage of voicemails
  • Team notification via Slack/webhook

State flow (business hours): PENDING -> CONNECTED -> DISCONNECTED

State flow (after hours): PENDING -> ANSWERED -> DISCONNECTED

Example

1@client.on(events.INCOMING_CALL)
2async def after_hours_handler(call: ActiveCall):
3 current_hour = datetime.now().hour
4 is_business_hours = 9 <= current_hour < 17
5
6 if is_business_hours:
7 # During business hours: connect to the original callee and leave
8 await call.connect()
9 await call.close()
10 return
11
12 # After hours: AI takes a message
13 await call.answer()
14 await call.send_audio(
15 await tts.synthesize(
16 "Thank you for calling. Our office is currently closed. "
17 "Please leave a message and we'll get back to you "
18 "on the next business day."
19 )
20 )
21
22 # Record the caller's message
23 audio_chunks = []
24 async for chunk in call.audio_stream():
25 audio_chunks.append(chunk)
26
27 # Detect end of message (silence detection via AI)
28 if await ai_model.detect_end_of_message(chunk):
29 break
30
31 # Transcribe and store the message
32 full_audio = b"".join(audio_chunks)
33 transcript = await stt.transcribe(full_audio)
34
35 await db.save_voicemail(
36 caller=call.caller_number,
37 audio=full_audio,
38 transcript=transcript,
39 )
40
41 # Notify the team
42 await slack.send_message(
43 channel="#incoming-calls",
44 text=f"Voicemail from {call.caller_number}:\n{transcript}",
45 )
46
47 await call.send_audio(
48 await tts.synthesize("Thank you. Your message has been recorded. Goodbye.")
49 )
50 await call.disconnect()

How It Works

  1. When a call arrives, the handler checks the current time
  2. During business hours: the call is connected to the original callee using connect() without answering, and the agent leaves with close(). The caller goes straight to ringing the callee.
  3. After hours: the AI answers, plays a voicemail prompt, and records the caller’s message
  4. The AI detects when the caller has finished speaking (silence detection)
  5. The recorded audio is transcribed using a speech-to-text service
  6. Both the raw audio and transcript are saved to the database
  7. A notification is sent to a Slack channel (or any webhook) with the caller’s number and transcript
  8. The AI confirms the message was recorded and ends the call

Key Commands Used

  • connect() - Route to the original callee during business hours (pre-answer)
  • close() - Leave the call after connecting the caller to the callee
  • answer() - Answer for voicemail after hours
  • audio_stream() - Record the caller’s message
  • send_audio() - Play the voicemail prompt
  • disconnect() - End the voicemail call after the goodbye prompt