Conversation recording
When enabled for a project, VoiceThere stores voice-session audio (user microphone + agent TTS playback) for dashboard playback on the session detail page. Recording is opt in— default off — and scoped to the authenticated project's settings and subscription. Cross-project access is denied.
Where to configure
- Dashboard: Project overview → Session settings → Conversation recording (
conversation_recording_enabled) and Metered recording overage (conversation_recording_metered_overage_enabled). - CLI:
voicethere projects session-settings list/voicethere projects session-settings set conversation_recording_enabled <true|false> - API:
PATCH /projects/:projectId/session-settings— see Control plane API.
Defaults: conversation_recording_enabled is false; conversation_recording_metered_overage_enabled is false. Settings apply on the next Deploy to cloud.
Included minutes & overage
Each subscription tier includes a monthly pool of recorded minutes (UTC calendar month). Partial minutes bill as one minute. Retention follows your plan.
| Plan | Included min / month | Retention |
|---|---|---|
| Free | 60 | 7 days |
| Budget | 120 | 14 days |
| Budget+ | 240 | 14 days |
| Advanced | 500 | 31 days |
| Ultimate | 1,000 | 31 days |
Rollover vs metered overage
With metered recording overage off (default), unused included minutes at the UTC month boundary roll into a capped minute bank(bank size capped at one month's included allowance). Recording stops when included + bank are exhausted.
With metered recording overage on, unused minutes do not roll over. Minutes past included + bank bill at 1 credit per minute on paid tiers (Free cannot use metered recording overage). Metered overage requires org billing readiness — a payment method on file and effective metered toggles — same gate as session billable minutes. See Billing & usage credits.
Dashboard playback
Open Project → Sessions → session detail. When recording was enabled for the project at session time, an audio player loads a signed URL for the stored session mix. If recording is disabled or no audio was captured, the panel explains how to enable recording on the project.
Agent recording controls
Even with the project setting on, your agent decides when audio is written. Use @voicethere/agent helpers with the session id — the runner owns capture. Typical reasons to call them:
- Consent — only
startRecordingafter the caller agrees; if they decline, never start (orstopRecordingimmediately). - Sensitive input — when the caller is about to share a card number, SSN, password, or other PII,
pauseRecordingso those frames are omitted from the file;resumeRecordingafterward. - End of capture —
stopRecordingwhen the recorded part of the call is finished (session end or mid-call).
Project setting conversation_recording_enabled must be true (and deployed) or the runner will not ingest audio even if you call startRecording. Check ctx.recordingAvailable on onSessionStart before prompting for consent. Plans still need remaining included, bank, or metered allowance.
Recording helpers return a promise that resolves when the runner acknowledges the control message. Local verify runs without a runner parent resolve immediately with reason: "local_mock" so laptop testing never blocks on IPC.
Skip recording when the customer declines
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)) {
const result = await stopRecording(sessionId);
if (!result.ok) return;
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 collecting sensitive information
import {
defineAgent,
pauseRecording,
resumeRecording,
speak,
startRecording,
stopRecording,
} from "@voicethere/agent";
export default defineAgent({
async onSessionStart({ sessionId, recordingAvailable }) {
if (!recordingAvailable) return;
const result = await startRecording(sessionId);
if (!result.ok) return;
},
async onUserSpeechFinal({ sessionId, text }) {
// About to collect payment details — omit audio until done
if (/credit card|card number|cvv|social security|password/i.test(text)) {
const pause = await pauseRecording(sessionId);
if (!pause.ok) return;
await speak(
sessionId,
"I will pause recording while you share that. Say continue when you are done.",
);
return;
}
if (/\bcontinue\b|done|finished/i.test(text)) {
await resumeRecording(sessionId);
}
},
async onSessionEnd({ sessionId }) {
await stopRecording(sessionId);
},
});Multi-tenant isolation
Recordings, minute banks, and playback URLs are keyed to the projectthat owns the session. API routes resolve the project from your API key or dashboard session — never from a client-supplied project id alone. One project cannot stream or bill against another project's recording allowance.
CLI examples
# Enable recording (default off) voicethere projects session-settings set conversation_recording_enabled true voicethere deploy --wait # Rollover mode (default) — bank unused minutes at month end voicethere projects session-settings set conversation_recording_metered_overage_enabled false # Metered overage — 1 credit/min past included + bank (paid tiers + billing ready) voicethere projects session-settings set conversation_recording_metered_overage_enabled true # Download a session recording (waits until ready, writes Opus file) voicethere sessions recording <orchestratorSessionId> --wait --output ./session.opus # Metadata only (status, duration_ms, …) voicethere sessions recording <orchestratorSessionId> --json
Related
- Conversation history — STT/TTS text transcripts (separate from audio recording)
- Billing & usage credits
- Runner settings