Conversation recording with agent pause and resume
August 23, 2026 · release
@voicethere/agent 0.4.0 · @voicethere/cli 0.12.0
VoiceThere can now store voice-session audio when you opt in per project — user microphone plus agent TTS — with playback on the session detail page and CLI download for local copies. Your agent decides when capture runs so you can honor consent and skip sensitive audio.
What shipped
- Opt-in per project —
conversation_recording_enableddefaults to off. Turn it on in Session settings and deploy. - Included minutes — Free 60, Budget 120, Budget+ 240, Advanced 500, Ultimate 1,000 recorded minutes per UTC month (retention follows your plan).
- Rollover or metered — With metered recording overage off (default), unused minutes roll into a capped bank at month end. With metered on, unused minutes do not roll over; extra minutes bill at 1 credit/min when billing and a payment method are ready (paid tiers only).
- CLI download —
voicethere sessions recording <id> --wait --output ./session.opus(or--jsonfor metadata). - Agent controls —
await startRecording,pauseRecording,resumeRecording, andstopRecordingfor consent gates and PII pauses (paused audio is omitted from the file). CheckrecordingAvailableon session start; local verify resolves withlocal_mockso laptop runs do not block on a runner parent. - Project-scoped — Recordings, banks, and playback URLs belong to the authenticated project only.
Try it
- Docs: Conversation recording
- Dashboard: Project overview → Session settings → Conversation recording
- Subscriptions: compare included minutes on Plans
Enable recording and deploy:
voicethere projects session-settings set conversation_recording_enabled true
voicethere deploy --wait
Download a recording after a session ends:
voicethere sessions recording <orchestratorSessionId> --wait --output ./session.opus
Only start recording after the caller agrees:
import { defineAgent, speak, startRecording, stopRecording } from "@voicethere/agent";
export default defineAgent({
async onSessionStart({ sessionId, recordingAvailable }) {
if (!recordingAvailable) return;
await speak(
sessionId,
"This call may be recorded for quality. Say yes to allow recording, or no to continue without it.",
);
},
async onUserSpeechFinal({ sessionId, text }) {
const answer = text.trim().toLowerCase();
if (/\bno\b|do not|don't|decline/.test(answer)) {
await stopRecording(sessionId);
await speak(sessionId, "Understood — we will not record this call.");
return;
}
if (/\byes\b|ok|okay|agree|allow/.test(answer)) {
const result = await startRecording(sessionId);
if (!result.ok) return;
await speak(sessionId, "Thanks — recording is on.");
}
},
});
Pause while the caller shares sensitive details (card numbers, passwords, and similar) so those frames never land in the recording — see the full pause/resume example in the docs.
For metered overage, add a payment method under Organization → Usage and enable metered recording overage on the project — see Billing & usage credits.