Voicemail
Record and manage voicemails for missed calls with persistent storage on-chain.
How It Works
When a call is missed and the caller chooses to leave a voicemail:
- Audio is recorded from the caller
- Voicemail metadata is stored on-chain
- Audio file is stored on decentralized storage (IPFS)
- Recipient receives notification of new voicemail
Recording Voicemail
After Missed Call
// Listen for missed call
dial.on('call:missed', async (call) => {
// Prompt caller to leave voicemail
const recording = await dial.voicemail.startRecording({
callId: call.id,
maxDuration: 120 // seconds
});
});Manual Recording
const voicemail = await dial.voicemail.record({
to: '0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb',
maxDuration: 120
});
// Stop recording manually
await dial.voicemail.stopRecording(voicemail.id);Voicemail Object
interface Voicemail {
id: string;
from: string; // Caller wallet address
to: string; // Recipient wallet address
audioUrl: string; // IPFS URL
duration: number; // seconds
timestamp: Date;
isRead: boolean;
transcription?: string; // AI-generated transcription
}Receiving Voicemails
Listen for New Voicemails
dial.on('voicemail:received', (voicemail) => {
console.log(`New voicemail from ${voicemail.from}`);
console.log(`Duration: ${voicemail.duration}s`);
console.log(`Listen: ${voicemail.audioUrl}`);
});Get All Voicemails
const voicemails = await dial.voicemail.getAll({
limit: 20,
unreadOnly: false
});Get Unread Voicemails
const unread = await dial.voicemail.getAll({
unreadOnly: true
});
console.log(`You have ${unread.length} unread voicemails`);Playing Voicemail
const voicemail = await dial.voicemail.get(voicemailId);
// Play audio
const audio = new Audio(voicemail.audioUrl);
await audio.play();
// Mark as read
await dial.voicemail.markAsRead(voicemail.id);Transcription
AI-powered automatic transcription is available:
// Get voicemail with transcription
const voicemail = await dial.voicemail.get(voicemailId);
if (voicemail.transcription) {
console.log('Transcription:', voicemail.transcription);
}
// Request transcription if not available
if (!voicemail.transcription) {
const transcription = await dial.voicemail.transcribe(voicemail.id);
console.log('Transcription:', transcription.text);
}Voicemail Settings
Set Greeting
// Record custom greeting
const greeting = await dial.voicemail.setGreeting({
audioFile: greetingFile,
duration: 10
});
// Or use text-to-speech
await dial.voicemail.setGreeting({
text: 'Hey, you\'ve reached my Dial. Leave a message!',
voice: 'en-US-Standard-A'
});Get Current Greeting
const greeting = await dial.voicemail.getGreeting();
console.log('Greeting URL:', greeting.audioUrl);Enable/Disable Voicemail
// Enable voicemail
await dial.voicemail.enable();
// Disable voicemail
await dial.voicemail.disable();
// Check status
const isEnabled = await dial.voicemail.isEnabled();Voicemail Management
Delete Voicemail
await dial.voicemail.delete(voicemailId);Archive Voicemail
await dial.voicemail.archive(voicemailId);
// Get archived voicemails
const archived = await dial.voicemail.getArchived();Save Voicemail
// Download voicemail file
const blob = await dial.voicemail.download(voicemailId);
// Save to device
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = `voicemail-${voicemailId}.mp3`;
a.click();Complete Example: Voicemail Inbox
import { useState, useEffect } from 'react';
import { DialClient, Voicemail } from '@dial/sdk';
export function VoicemailInbox({ dial }) {
const [voicemails, setVoicemails] = useState<Voicemail[]>([]);
const [playing, setPlaying] = useState<string | null>(null);
const [audio, setAudio] = useState<HTMLAudioElement | null>(null);
useEffect(() => {
loadVoicemails();
// Listen for new voicemails
dial.on('voicemail:received', (voicemail) => {
setVoicemails(prev => [voicemail, ...prev]);
});
return () => {
dial.off('voicemail:received');
if (audio) audio.pause();
};
}, [dial]);
const loadVoicemails = async () => {
const vms = await dial.voicemail.getAll({ limit: 50 });
setVoicemails(vms);
};
const playVoicemail = async (voicemail: Voicemail) => {
// Stop current playback
if (audio) {
audio.pause();
}
// Play new voicemail
const newAudio = new Audio(voicemail.audioUrl);
await newAudio.play();
setAudio(newAudio);
setPlaying(voicemail.id);
// Mark as read
if (!voicemail.isRead) {
await dial.voicemail.markAsRead(voicemail.id);
setVoicemails(prev =>
prev.map(vm =>
vm.id === voicemail.id
? { ...vm, isRead: true }
: vm
)
);
}
// Handle end of playback
newAudio.onended = () => {
setPlaying(null);
};
};
const stopPlayback = () => {
if (audio) {
audio.pause();
setPlaying(null);
}
};
const deleteVoicemail = async (id: string) => {
await dial.voicemail.delete(id);
setVoicemails(prev => prev.filter(vm => vm.id !== id));
};
const formatDuration = (seconds: number) => {
const mins = Math.floor(seconds / 60);
const secs = seconds % 60;
return `${mins}:${secs.toString().padStart(2, '0')}`;
};
const unreadCount = voicemails.filter(vm => !vm.isRead).length;
return (
<div className="voicemail-inbox">
<h2>Voicemail ({unreadCount} unread)</h2>
<div className="voicemail-list">
{voicemails.map(vm => (
<div
key={vm.id}
className={`voicemail-item ${!vm.isRead ? 'unread' : ''}`}
>
<div className="info">
<strong>{vm.from}</strong>
<span>{vm.timestamp.toLocaleString()}</span>
<span>{formatDuration(vm.duration)}</span>
</div>
{vm.transcription && (
<p className="transcription">{vm.transcription}</p>
)}
<div className="actions">
{playing === vm.id ? (
<button onClick={stopPlayback}>⏹️ Stop</button>
) : (
<button onClick={() => playVoicemail(vm)}>▶️ Play</button>
)}
<button onClick={() => deleteVoicemail(vm.id)}>🗑️ Delete</button>
</div>
</div>
))}
</div>
</div>
);
}Visual Voicemail
Get a visual representation of the audio waveform:
const waveform = await dial.voicemail.getWaveform(voicemailId);
// Returns array of amplitude values (0-1)
console.log(waveform.data); // [0.1, 0.3, 0.5, 0.7, ...]Voicemail Notifications
Configure how you want to be notified:
await dial.voicemail.setNotificationPreferences({
push: true, // Push notifications
email: true, // Email notifications
includeTranscription: true // Include transcription in notification
});Storage and Costs
- Voicemail audio is stored on IPFS (decentralized)
- Metadata is stored on-chain
- First 100 voicemails per month: free
- Additional storage: 0.001 SOL per voicemail
Next Steps
Last updated on